Table of Contents
The main aim from this chapter is getting into the guts of the Model-View-Controller framework. From an eBox developer is not required to get into if it is not strictly necessary. However, it could be useful to use it properly, to enhance it in some way or, what is more, to add features not already addressed before.
The main logic related to the data model is encapsulated on
EBox::Model::DataTable
. Its constructor requires at least
a GConf module, i.e. an eBox module, a directory to store the data model and a Gettext
domain which normally match with the GConf module one. The
model description is instanced
just one using the Singleton method pattern at table
method.
As the Figure 7.1 depicts, there are
two main data model DataTable
and
DataForm
which represents the template system to be
used by real data models such as EnableForm
or
ConfigureLogTable
.
Data manipulation is done by
addRow
, removeRow
and
setRow
, they are convenient methods to add, remove and
update rows. The fields to fill the row are tailored to simplify and speed
up the data input management from the HTTP request through a CGI. Moreover, a typed
version is intended to be developed to ease the internal management and the exposed
API as Section 1.5.3 requires. For instance, to add
a member in the member table you
may use this piece of code:
$model->addRow( ( name => 'admin', ipaddr_ip => '192.168.1.2', ipaddr_mask => '32', macaddr => '00:50:57:D0:11:08' )
The data from a model is stored and retrieved from GConf, some caching is done in order to speed up the data access times. In order to describe the GConf structure, it had better to use the result from gconftool command:
Example 7.1. GConf structure from a model
data_version = 1 /ebox/modules/objects/objectTable: /ebox/modules/objects/objectTable/keys: version = 44 /ebox/modules/objects/objectTable/keys/x6666: readOnly = false name = RRHH /ebox/modules/objects/objectTable/keys/x6666/members: /ebox/modules/objects/objectTable/keys/x6666/members/keys: version = 1 /ebox/modules/objects/objectTable/keys/x6666/members/keys/memb44: readOnly = false name = Claudia ipaddr_ip = 192.168.1.92 ipaddr_mask = 32 /ebox/modules/objects/objectTable/keys/x1850: readOnly = false name = MKT /ebox/modules/objects/objectTable/keys/x1850/members: /ebox/modules/objects/objectTable/keys/x1850/members/keys: version = 3 /ebox/modules/objects/objectTable/keys/x1850/members/keys/memb9612: readOnly = false name = Florencia ipaddr_ip = 192.168.1.42 ipaddr_mask = 32 /ebox/modules/objects/objectTable/keys/x1850/members/keys/memb9390: readOnly = false name = Hugo ipaddr_ip = 192.168.1.46 ipaddr_mask = 32 /ebox/modules/objects/objectTable/keys/x1850/members/keys/memb2675: readOnly = false name = Silvina ipaddr_ip = 192.168.1.43 ipaddr_mask = 32
As you may see, the object data model stores two objects RRHH
and MKT, which the former saves one and the latter three members.
The data_version
indicates the data structure version in the same
sense as Section 3.9 explains. Each data model stores
their values under keys/id
directory, the id is obtained using
get_unique_id
as Section 3.3 describes.
Version property is used by caching scheme, as you might guess,
which is currently done per data model basis. As each object data model row has several members using
the member data model, they are stored within the object directory as if another model.
Each type has its value stored in GConf, for instance the field name
for object x6666
has as value RHHH
.
readOnly attribute indicates whether the row is read only or not.
With regard to form data model, the GConf structure is quite simplified flattening
the keys/id
to the main GConf directory to let the form
developer see its content easily.
Model relationship is describe through EBox::Types::HasMany
and
through EBox::Types::Select
and whose management is done by
EBox::Model::ModelManager
and
EBox::Model::DataTable
. The former singleton
class coordinates all the available models along eBox, see
Section 7.4 for details. Currently, there are two kind
of relationships:
Determined by a select type which fetch its possible values or
options from a foreign model, that is, from a value which is stored
in a field in another model. To describe so, the
foreignModel
and foreignField
must be set at table description. The model manager will store the
one-to-one relationship to maintain the referential integrity.
The HasMany relationship represents that a single field from
a data model stores another data model. The inner model looks like
a submodel within the outer model and thus the rows
and printableValueRows
methods must return
the information within that model per row. Likewise, when a row
with a HasMany type is removed, the inner data model content is
deleted as well.
Furthermore, the Observer pattern
is applied to the data models as well. The models can subscribe to actions performed
in foreign models such as addition, removal or updates. In order to achieve so, the
table description must have notifyActions
attribute as an array
reference indicating which are models if you are interested to. So the model manager notifies an action
is performed by a model calling notifyForeignModelAction
method on
the observer.
Whenever an changing state action is performed, the data model asks the model manager
if any of other modules is using that row. To determine
whether an observer is using a row or not, it is asked by
calling warnOnChangeOnId
when an
update is the performed action or
isUsingId
on removals as well as a
search on the observer model data. If there are observers
subtle to be changed and automaticRemove
is
set, a warning is shown before forcing the operation. If automaticRemove
is not set, the data model must specify how it should act subscribing to the changing actions
as it is described above instead.
The current eBox types selection is quite small and limited. We can see at first glance how its class structure at Figure 7.2.
As we can see Abstract
manages the essential information for every
eBox type. That is, their common attributes such as optional
,
editable
, printableValue
, etc. It also provides
the main methods not to be overridden such as setMemValue
,
restoreFromHash
and so on. Basically, an eBox type allows the
developer abstracting from GConf storage and user input correctness since their handling
is automatic. Furthermore, an eBox type is responsible for determining which setter
and viewer must be used in eBox user interface by asking to HTMLSetter
and HTMLViewer
respectively.
Firstly, in order to add a new eBox type is required to look over Figure 7.2 to check it if something similar has been developed before and just a class extension is required. Once we are sure a new type is needed for our models, these following methods, at least, must be overridden to make the type work:
_setMemValue
Set the memory value for the type. It is assured that this method will be called if only there is something to fill the type and its content is valid.
_storeInGConf
Store the given type in a GConf directory from a GConfModule. The expected behaviour is if it has no value to store, remove any previous stored data.
_restoreFromHash
Restore the type value from a hash reference which
usually comes from hash_from_dir
returned value.
_paramIsValid
Check the correctness from the parameters passed. It assures that it is something to be checked
_paramIsSet
Check if the given parameters contain the data needed to fill the type, i.e. it exists and it is not empty
_setDefaultValue
Set the default value for the type
Apart from overriding these methods, it should set HTMLSetter
,
HTMLViewer
and type
on the constructor.
The former two attributes determines which mason template, giving its path, must be
used to set and show the type value respectively. The latter must be the class name
in lower case. Methods compareToHash
, isEqualTo
and printableValue
are recommended to be overridden.
The common eBox types are in ebox
base debian package, however
it is also possible to develop a custom type which will be used only by a single
eBox module or by any of its dependencies. This happens to
SinglePortService
which depends on the services
eBox module.