Butler Documentation Wiki
Welcome to the Butler's oficial documentation. If you find something confusing or with a lack of explanation, please, send an email to firstname.lastname@example.org. We try to solve it as soon as possible. Thanks for your collaboration and we hope that this wiki helps you.
Butler provides a multi-instance configuration that allows you to
define all the connections that you need. This configuration
is inside the file
/app/databases.ini and have
the next structure:
Every block defines one instance. By default, Butler access to the
intance with the name:
For create the database connection, Buler use
adapters plus a singleton pattern,
that ensure no open more the one connection for the same instance.
And what happens with the destructor? Don't worry,
close the connection automatically in the destructor method.
For more information about the creation of instances and query execution, click here.
By default, Butlers works with a generic router that use the next
controller is the result of remove
_controller of our controller,
task, the name of the public method
that we like to execute.
However, it's possible that we like to create custom routes. For this,
Butler have one file,
where we can define all the routes that we need. This file, use
the next structure.
controller: Name of the controller that resolve the route (fullname of the class)
url: An internal name (usefull for the debug)
regex: The rule that provides the match of the URL
params: An array that defines all the params that this route receives. If the regex have parenthesis statements (
(.*):), the params will be filled in order of resolution in the regex match. If we define a value in this array, is the default value (if isn't filled by the regex matches, will have this value).
task: The public method of the controller that we like to execute
resource: The shortname of the controller (Error_controller => error)
cacheable: Defines if this route can be cached
The environment vars of Butler are defined in the
/app/configuration.ini file. In it, we can
define all the vars that we need and create groups for the different
environments. The configuration result is saved in the class
that provides a method called
that returns the value of the config var with the name $name.
By default, the vars the we define are the vars that are in the
block plus the variables that are in the current enviroment block
(test, prod, integration...). If the same var is defined in the
config block and in the current environment
block, the var overrides their value with the value defined in the
var of the current environment block.
Access Control List (ACL) /app/acl.ini
The access management was configured in the
/app/acl.ini file, that provides
a hierarchy of roles, resources and subresources, and their
The definition of this terms is something like:
- Role: Type of user
- Resource: Controllers Group
- Subresource: Everyone of the controllers that we have in the application
And below...the steps for made this file:
rolesblock, we list all the roles that we like to provide in our platform, assign it to everyone which is their parent. If is a root role, we asign a blank value (
resourcesblock, we list all the groups of controllers that we like to create, assign it a
The next step is the
subresourcesblock. In it, we list all the controllers that we have in the application and we assign to which block they belong.
The last step is create one block for every role and inside, we
list all the permissions createing strings like:
role.resourceOrSubresource.task = allow/deny
rolewe put one of the roles that we define in the first block.
resourceOrSubresourcea resource or subresource.
task, one of the public methods that are inside the subresource or
all, that determinates the entire set of public method that we can execute inside this resource/subresource.
If we assign a
allowvalue, we allow the access. If we assign a
denyvalue, we deny the access.
Below, an example of a posible
Butler provides a place to concentrate all the scripts (CSS & JS) that
will be needed in our requests. For do this, use 4 files, 2 for the
and 2 for the backend
All the CSS that we define in this files will be included at the end of the
tag and all JS just before the close of the
Below, an example of the content of this files:
Request to Response
All the requests that receives the server are rewrited to point to the
index.php file that are present in the
public folder. Don't worry if your virtualhost
doesn't point directly to the public folder, because Butler have
.htaccess file in the root folder
that rewrites the request to the
Root folder /.htaccess file
When we are sure that we are in the public folder, we force to execute
index.php file. This rule only have effect
if the resource that the user solicite via URL doesn't exists, because
if the resource exists (for example a css or js file), Butler allows
the direct access to this file.
Loading Classes /app/config/autoloader.php
The automatic class loading use the next rules:
|Type||Classname Pattern||Filename Pattern||Path|
/app/autoloader.phpfile, for ensure that all the classes can be founded for the application.
After set all the global vars and define the class autoloader, the
execution path cross through the
file, that provide a place to define all the functions that we need
to execute for ensure a good initialization of our application. When the
bootstrap file is called, all the functions that start with
will be executed in the same order that are defined in the file
We are initialized! Now, we need to dispatch our request. For this, Butler
Fw_Dispatcher, that is the responsable of process the request. In it,
Butler, instance the Router, the
and manage the Request Cache.
The Dispatcher file can't know alone which is the controller that we need for process the current request. For this, needs the help of the Router, that centralize all the route rules of our application. By default, use the next one:
If we like to define another type of routing, we must to extend/modify the
Fw_Router class. If we only need to create
that some URL's have an specific behaviour, we can create custom
routes in the routes file (view Configuration/Routes).
By default, the cache is not enabled. If we like to enable id, we only need
to change the value of the
cache_mode configuration var
true, that is inside the
When the cache is enabled, all the routes that have the
true in the
file, creates a file that will be returned for all the request to this
route. This field expires in the beggining of the next hour.
All the cache files are genereted in the
and contains all the request html with the exception of the debug bar. The name pattern
of this files is
controller is the controller's name,
the name of the method executed,
Y_m_d_H the year, month, day and hour
urlparams the result of
_ all the params of the URL that aren't part of the
http://mydomain.com/controller/task/2?p1=v1, generates the
The Controllers in Butler doesn't have lots of differences between the generic controller that defines the MVC. In it, we found some task, that are defined using public methods. In this methods, we can call to different Models and Views, creating the custom response that we like to solve the current request.
All the Controllers needs to extend of
and needs to be placed in the
Only for extends this class, we obtain the next execution path:
pre method can be extended and allows us
to execute a routine before the execution of the task. This routine
will be executed in all the tasks of this controller. The same
happens with the
post post, that allows us
to create a post execution routine in all the tasks of this controller.
Fw_Controllermethods are public, but is better doesn't extend it, because are very linked with the core functionalities.
Below, an example of a Controller:
The Layouts are page renderization structures. In other words, every one of the different styles that have our application. By default, Butler have 3 (blank, admin and defaut), but you can create more or modify the default ones.
We can create all the Layouts that we need and for use it, we only need to assign it in the Controllers constructor (if like to have the same layout for all the tasks of this Controller) or task by task (if we need that only affects to this task).
One of the most important things to take in account is the
$html variable, that contains the
specific content of our task. In the place that we put this
variable, the view will be renderized.
Fw_CrudController is a class that extends
Fw_Controller and offer us the
posibility to manage the registers of Database Table very easily
Contains, principaly, 5 functions:
Creates a table view that contains fields for create custom filters for show only the records that we like. This search using filters, we can use the next sintax:
- Exact Search:
- Interval Search:
- Approximate Search:
For configure the columns that appears in this view, we need to set the
admin_paramsattribute in the
__constructmethod of our controller, that use the next sintax:
Title Nis the name of the column header in the table view y
fieldNis the name/alias of the field in the query that obtain the result of the table.
An example of the admin view of User_Controller class(
- Exact Search:
An example of the edit view of the User_Controller class(
An example of the add view of the User_Controller class (
The Models, like the Controllers, have the traditional structure
of a MVC Model. In this case, we found that all the Models needs
to extend from the
Fw_Model class, that
contains the basic methods for access to the table information.
This methods are:
getData($count, $limit, $limitstart, $cols)
getDataForSelect($table, $field, $join, $where)
setNMRelationships($nTable, $mTable, $idNTable, $aIdMTable)
Butler provides a Register Pattern that allow you to store variables and objects that after you like to restore. For use it...you only need to do this:
For get an instance and execute a query, we need to write something like:
CCC (Combine Compress and Cache)
Butler offers the posibility of combine, compress and cache
all the JS and CSS in only one file (one for every extension).
For do it, you only need to go to admin panel and do clic
in the option
Minify Scripts, that
is in the
Tools menu. This action
will combine all files that we defined in the scripts configuration
files (view Configuration/Scripts)
and generetes one file for every type of extension and environment
(backend and frontend).
By default, this files are generated in the next folders:
Inside the admin panel, we have the posibility to do a full
dump or a only structure dump of the default database that use
local). If you like to do dumps
of other instances, you need to change the core a little bit or
wait for the next releases.
The text internationalization of Butler is made with the PHP native function
getText(), that also can be called with the
_(). For use it, you only need
to create one folder for every language that you like to use and, inside,
that are loaded inside the application in the
For create the
you can use some applications. However, one of the most easy to use is
a lightweight and multi-platform software that allow us parse all
the the application and obtain all the texts that we use automatically.
Butler provides a Debug Toolbar that allow us to work more confortable
in local and test environments. For enable it, you only need to set
After that, in every request, you can view an icon like . If you click it, a toolbar with different sections will be open. Every section can be clicked for obtain more information.
This sections are:
In this section we found all the queries that was executed in this request, which is their status, the execution time and how many rows was affected for they.
The number in parenthesis is the total number of queries executed in the current request.
In this section are listed all the files that we load in the current request and, in parenthesis, the max memory used for process the request.
When we are developing is very noisy view the notices, warning and errors in the middle of our html. For this, this section groups all of them and we can view it more easy and grouped by error type.
The number in parenthesis is the total of errors that the error handler found (
All the headers of our request.
In this section we found all the vars that cames with the request (
$_SERVER), the global vars and all the constants that was defined for process the current request. Also, here there are all the vars that we put in the Register (view
Fw_Register).Sometimes is useful add variable to the Fw_Register and check their values in the debug, because using alternatives like
var_dump, we don't know exactly in which place of the DOM appears our result.
Total time that the server spends for process the request.