-
Notifications
You must be signed in to change notification settings - Fork 4
DeveloperGuide
CmFive is a framework for developing web based business applications.
The main focus is on facilitating fast development of functionality with minimal boilerplate code.
The framework provides object persistence features and a routing controller with actions and templates.
The framework follows strict module based isolation of code with hooks and listeners provided for integration.
The framework comes with a number of modules providing UI for common models including Users, Tasks, Time logs, Wiki, Files.
The related CRM project is a closed source module for CmFive that provides Accounts, Projects, Invoicing, Expenses, Hosting and Staff.
The framework provides well tested libraries for persistence, template rendering and HTML generation from records.
A good place to learn about the framework is to look at the example module. The tasks module provides more complex examples.
A cmfive site includes the following top level files and directories config.php - the main configuration file for the site index.php - point of entry for all requests system - cmfive source code modules - module folders for this install are placed here cache - temporary items backup - storage location for dumps generated by the backup module log - log files are written here storage - provides a single folder to hold cache, backup, uploads and other files written by the web server uploads templates lib doc - generated api doc
A typical installation symlinks the cmfive repository system folder and copies other key top level files into the project folder. Other folders are created by the system on demand.
Inside the system folder are the following important files and directories composer modules classes AspectModifiable.php AspectSearchable.php AspectVersionable.php Config.php CSRF.php DbMigration.php DbObject.php DbPDO.php DbService.php DbTable.php History.php html a.php button.php form.php input.php SessionManager.php html.php html rendering functions functions.php miscellaneous functions web.php request handling and routing composer.json composer file for system dependancies composer dependancies are also configured in modules and the admin menu item for composer update handles unifying the dependancies.
All HTTP request to a cmfive application are routed through index.php
The request url is used to determine which module and action should handle the request Url format is //-/ An action can choose to handle POST, GET or ALL requests by convention of function eg doSomething_POST()
A module folder contains the following important files and directories
config.php
eg
<?php
Config::set('example', array(
'active' => true,
'path' => 'modules',
'topmenu' => true,
'search' => array(
"Example Data" => "ExampleData",
),
'widgets' => array(),
'hooks' => array('core_dbobject','example'),
'processors' => array(),
));
options
active
the module can be deactivated by changing active value
path
path must be modules or system/modules
topmenu
should the module provide menu items
to customise menu items for this module, create a navigation function in the main service class.
search
label and database name to be used when searching records from this module
widgets
hooks
processors
models
php model definition files
service classes
actions
files in this folder can be routed to using an appropriate url
where example/actions/edit.php contains a function called edit_ALL(), a request to the url http://domain/example/edit will include that php file and call the edit_ALL function
templates
when an action functions complete, output rendering is initiated using template files using a similar convention if one is available.
for example the availability of /example/templates/edit.tpl.php (and example/actions/edit.png) will trigger first the action code and then the template code.
The template code runs in a special context created by web for rendering.
Data is passed from actions to templates using web context.
ie $w->ctx("table","my table content"); means that the variable $table is available in the template.
install
this folder contains information required to build the database structure for this module
historically this was sql files
migrations using phynx is the new standard for defining a model.
migration scripts are inside the subdirectory migrations
migration scripts should not be modified once they are deployed, additional changes to a data structure should be defined and deployed as additional migration files.
help
files named <action>.help containing markdown content are automatically detected and deployed as context sensitive help.
tests
tests related to this module
<module>.roles.php
defines the roles available in this module.
the presence of a file called example.roles.php in the example module containing
function role_example_admin_allowed($w, $path) { return startsWith($path, "example"); }
enable a role based access type for users and groups.
<module>.hooks.php
<module>.listeners.php
CmFive supports highly customisable access controls around users, groups and roles.
Users can be assigned roles. Assignment to a role enables features or customisations dependant on how the code in a module interprets those roles.
Roles can be managed in association with groups. User are members of groups. Role can be assigned directly to users or to groups. A user inherits all the role of any groups they are assigned to.
CmFive tasks and wiki modules provide for association directly with users and offer additional access restrictions based on their models. Details are provided in per module documentation.
Most of the code related to authentication is through the auth module.
The AuthService class provides some key functions including
- allowed - determine if the logged in user is allowed access to a given URL.
- user - returns the current logged in user as a User object.
- hasRole($role) - checks if the logged in user has matching role.
- any many more
The user object has a function allowed which implements collation of a users roles and runs the global roles functions seeking a true result to allow access.
The AuthService allowed function basically relies on the user allowed function for the currently logged in user. The function caches its results as the allowed function is typically called many times during page rendering to determine whether elements should be rendered. For example, the generation of a menu calls allowed for each menu item.
Roles files provide one approach to customising behavior. Using role files, you can explicitly enable a list of urls that are allowed when a user has a role or apply other filtering techniques.
In each module there can be a file in the root module folder called roles..php . In these files are global functions named as role__allowed($web,$path). In checking access for a user, each associated role is checked by calling the matching global function if it exists. If any of these functions return true, access is granted. Note that a single role file that returns true incorrectly invalidates role based protection for ALL modules.
For example if user joe is associated with a role for wiki_user and is a member of group staff which is associated with roles for user and comments then the functions role_wiki_user_allowed, role_user_allowed and role_comments_allowed are called with the current url path.
Typically role files use the checkUrl as a shortcut for matching module/action/subaction eg inside wiki/wiki.roles.php
function role_wiki_user_allowed(Web $w,$path) {
return $w->checkUrl($path, "wiki", null, "*");
}
Means that users with wiki_user role are granted access if the path matches /wiki/*
The check for roles is made with every request to cmfive. The root level index.php calls Web->start, which calls AuthService->user()->allowed() where the relevant role files for this user are tested for access to the current URL.
Configuration options allow bypass of authentication for certain url endpoints.
system.allow_module enables access to a module where there is no role based allow rules.
Config::set("system.allow_module", array( "rest" ));
system.allow_action enables access to module actions where there is no role based allow rules.
Note that the following actions must be allowed for the system to work correctly.
Config::set('system.allow_action', array( "auth/login", "auth/forgotpassword", "auth/resetpassword", ));
system.allow_from_ip enables access to selected actions from a specific IP address
Config::set("system.allow_from_ip", array( "10.0.0.0" => array("action1", "action2"), ));
Model classes that extend DbObject can override the canView,canList,canEdit,canDelete functions to fine tune the access behavior per object. By default these functions all return true.
Alternative implementation of these functions typically takes roles into account. They will also typically consider an object field such owner_id.
These functions are not called automatically but must be used explicitly by developers to check object permissions before calling update,insert or delete. They can also be used in templates to fine tune template rendering based on object permissions. This should not be used as an alternative to properly designed queries in sourcing any data to be rendered.
Model files are stored in a modules models folder.
Models in CmFive are simple php classes extending the CmFive base class DbObject. The base class provides a number of features including persistence and validation.
Model classes correspond to data models representing persistent elements of the system.
$user=new User();
$user->name='fred';
if ($user=>validate()) {
$user->updateOrInsert();
}
.....
$user->delete();
The DbObject class relies significantly on convention in naming to implement automagic features
Magic Database object Subclasses should either have the same name as the DB table, or need to override getDbTableName() function.
- Define the Database Table Name (optional, see DbObject::getDbTableName()):`
public $_db_table = "";
All properties need to have the same name as DB table properties or need to be considered in getDbColumnName() function.
A subclass can define the following special properties for special handling:
- _* properties are considered transient not automatically saved to DB
- dt_* any property starting with dt_ will be transformed into seconds when loaded from DB and turned back into MySQL datetime format when saved to DB.
- d_* as above but data only
- t_* as above but time only
- is_deleted when exists will be set to 1 instead of deleting the table data on object::delete(), to really delete the data in the DB ::delete(true) must be called!
- Auditing of inserts and updates happens automatically to an audit table.However this can be turned off by setting
public $__use_auditing = false;
- DbObject supports the use of the following 'Aspects' which can be added to any object using a magic '$_' property:
- Aspects can be removed in the case of class inheritance. If the parent class has
-
public $_searchable;defined then this can be removed by a child class using: -
public $_remove_searchable. However further childclasses can no longer add this aspect!
-
- SearchableAspect ->
public $_searchable;This Aspect does not add any public functions to the object, but extends the insert/update/delete behaviour so that an index record is created (or updated) in the table object_index which contains the object_id reference and a sanitised string of the content of the source object's fields for fulltext retrieval. Per default all properties (except thos in the $_exclude_index array) are concatenated and included in the index. In order to add custom content (eg. from dependent tables) create the following: function addToIndex() {} Which should return a string to be added to the indexable content. All sanitising and word de-duplication is performed on this.
- Aspects can be removed in the case of class inheritance. If the parent class has
The validate function responds to the _$validation property of a DbObject.
- Automagic Select UI Field Hints, see getSelectOptions() for more info.
static $_<fieldname>_ui_select_string = array("option1","option2",...);static $_<fieldname>_ui_select_lookup_code = "states";static $_<fieldname>_ui_select_objects_class = "Contact";static $_<fieldname>_ui_select_objects_filter = array("is_deleted"=>0); - title when exists will be automatically used for object::getSelectOptionTitle() method
- name when exists and title doesn't exist then will be used for object::getSelectOptionTitle() method
DbService is the base class for DbObject and provides functions for searching objects, request parsing, cache and transaction management. Service classes in CmFive extend DbService directly. Service classes provide functions relating to many records.
DbService provides the getObject($class, $idOrWhere, $use_cache, $order_by )
DbService provides the getObjects($class, $where, $cache_list, $use_cache, $order_by , $offset, $limit)
###Templates in Depth
###Layout cmFive provides a base layout that a module is rendered inside. The base layout provides the menu, a number of javascript libraries and mobile friendly foundation based layout. ###Html Helper Class The Html class provides a number of static methods for generating standardised HTML from records.
At the highest level, functions like multiColForm and multiColTable take arrays of configuration and render forms and lists. There is also support for UI widgets including date pickers and file uploaders.
You can add a counter to tabs by adding a span inside your tab header and giving it a special class. The class format is "cmfive__count-<html class you want to count>". I.e:
<span class='label secondary round cmfive__count-attachment'></span>
is what we use to count attachments for an object in the tab header.
Redirection ContextGlobal $modules Array Changing System Module Configuration Overriding Another ModuleGUI in admin section - admin users only Batch migrations - all pending migrations can be run as a batch and that set of migrations is saved as the batch set so they can be rolled back as a batch - create a migration for a module wizard in GUI - edit generated migration file - up and down function as inverse - ensure hasTable, hasColumn before addtable etc - id field replacement for biginteger - phynx docs in composer (online is a version ahead) - MyDevMigration extends CmFiveMigration extends Phynx/AbstractMigration - dropTable - override to rename name - addCmFiveParameters - list fields you DONT WANT - discuss option to improve API on drop tablecmfive uses the GitFlow branching model.CmFive is an open source GPL licenced software framework and business web application.
To contribute please send pull requests to https://github.com/2pisoftware/cmfive
Please ensure that all tests pass before submitting patches.