PHP's EASY MVC

                                                                    Phiber Framework

Getting Started

Welcome

Tired of plain PHP or from using your old bloated and messy framework?

Look no more, Phiber is what you're after

Shopping for a good framework might prove to be a tedious task not only because of the amount of available PHP frameworks. But mostly because learning a new framework just so you can test it properly, even if it might sound like the only right way to it, is not really an option for the majority of us. Not that learning a new framework is an easy thing to do any way. One might spend a "career" time just learning the quircks of his favourit framework. The strategy most developers use when looking for a framework to adopt is to look for how many people were actually sold to a given framework (community that is). You know, the herd mentality.
Having a community is certainly a great point in favour of any framework but it should not be decisive to say the least because YOUR NEEDS are specific to you and to your project they are NOT and will never be the community's point of focus.

Why?
You need a framework that enables you as a developer with a set of tools, components and concepts to help you cut through the boring routines and repetitive tasks so you can focus on your solution.
Phiber does not attempt to do your job or outsmart you. Other frameworks will tell that all you need is to define a class to be able to do CRUD (Create, Read, Update, Delete) operations on a table, or create class so the DDL is generated for you in an unnatural way only to discover later that your dear framework is killing your DB server by issuing queries that you never asked for. Soon enough you'll be asking what the PH is going on? The most automagic you'll see is due to PHP's autoloading capability and a set of conventions as to where files should be located. Phiber Framework is only ~2500 lines of code long ;)

Features

  • Very easy to learn (probably why you picked PHP in the first place)
  • Very easy to develope and deploy with Myo and Composer
  • Lightweight and very fast (150k uncompressed)
  • One-file easy configuration
  • Painless Routing (simple and RegEx/named params)
  • Drop-in architecture for plugins, modules and even controllers
  • True MVC (Models CAN communicate with views directly)
  • eventful (trigger and listen to events if you want to)
  • OOSQL ORM and Query builder (Zero configuration)
  • Entity generator (Design your DB like a DBA)
  • Use any library out there within your plugins, models or controllers
  • Myo command line tool to speed up development and prototyping

License

Phiber Framework is free for personal and commercial projects. Phiber Framework is released under the terms of the MIT license.


Working with Phiber


Install

1. Using composer
  composer create-project phiber/sample-app your-project-name

2. Using
Myo
Refer to Myo section in this doc.

Permissions

On linux, make sure your webserver has enough permissions for phiber to create/write files in the application folder.
Requirements
  • PHP >=5.3
  • Webserver (Apache, Nginx, IIS)
Front controller server config
To be able to use Phiber you'll need to configure your server to route all requests through index.php. There are multiple ways to make this happen, for example:
  • Apache .htaccess example
      
    		  RewriteEngine On
    		  RewriteCond %{REQUEST_FILENAME} -s [OR]
    		  RewriteCond %{REQUEST_FILENAME} -l [OR]
    		  RewriteCond %{REQUEST_FILENAME} -d
    		  RewriteRule ^.*$ - [NC,L]
    		  RewriteRule ^.*$ /index.php [NC,L]
    
    		  # if installed in a subfolder
    		  #RewriteRule ^.*$ /subfolder/index.php [NC,L]
    		  
              
  • Nginx example config
    		   try_files   $uri $uri/ /index.php?$args; 
    		  
  • Configuration

    All configuration properties are located in one file that should be provided as a parameter to Phiber on the index.php file.
     
    $phiber = new Phiber\wire('../application/config.php');
    The configuration file doesn't have to be called config.php
    • Timezone and Mode
    Timezone can (and should be) set in php.ini to avoid calling date_default_timezone_set() on each request. If you have no access to your php.ini you can set this value in the configuration file.
      public $PHIBER_TIMEZONE = 'Africa/Algiers';
    
    Phiber Mode refers to what environment this installation is serving. For now there is only one value that has a meaning for the framework which is "dev". If the Mode is set to "dev" Phiber will inspect and scan certain directories for changes. This is obviously a burden should it be activated on a production environment. Any other value will be taken as "non-dev" and will switch to use pre-compiled files generated on "dev" mode as a cache to prevent directory scan, file updates and other tasks. This will change over the time to include other modes that would affect the way Phiber works but we'll keep those changes backward compatible as much as possible.
      protected $PHIBER_MODE = 'dev';
    • Database configuration

    public $PHIBER_DB_DSN = 'mysql:host=127.0.0.1;dbname=databaseName';

    public $PHIBER_DB_USER = "root";

    public $PHIBER_DB_PASS = "password";
     
    If you use Myo to install the application
     myo app myapp
    After unpacking the sample application you'll be prompted for db configuration
     Would you like to configure myapp [yes]? (yes/no)
    You'll be asked to type in db credentials if you chose to.
    • Log configuration
     /**
       * Enable/Disable logging
       * @var boolean
       */
      public $PHIBER_LOG = true;
      /**
       * Default logging handler
       * @var string
       */
      public $PHIBER_LOG_DEFAULT_HANDLER = 'file';
      /**
       * Log filename
       * @var string A valid filename
       */
    public $PHIBER_LOG_DEFAULT_FILE = 'logfile.log';
    /** * Directory of the logs please set an absolute path. Must be writable by the server * @var string A Valid absolute path (directories will not be created for you) */
    public $logDir = null; /** * Sets log level inclusive to previous levels i.e setting it to 'alert' * will log 'alert' and 'emergency' level events and 'debug' will log everything * * 'emergency'; * 'alert'; * 'critical'; * 'error'; * 'warning'; * 'notice'; * 'info'; * 'debug'; */ public $logLevel = 'debug';
    /**
    * Stop execution on warnings
    */
    public $STOP_ON_WARNINGS = true; /**
    * Stop execution on user triggered warnings
    */ public $STOP_ON_USER_WARNINGS = true;
    • Session configuration
      /**
       * Session will be destroyed after 1800 seconds (30
       * minutes) of inactivity Alternatively set the value that you like in seconds
       */
      public $PHIBER_SESSION_INACTIVE = 1800;
      /**
       * The session id will be reginerated after 1800 seconds (30
       * minutes). Alternatively set the value that you like in seconds
       */
      public $PHIBER_SESSION_REGENERATE = 1800;
    • Path configuration
       /**
        * The absolute path to phiber library
        */
       protected $library = '/path/to/vendor/phiber/phiber/library';
       /**
        * The absolute path to the application folder
        */
       protected $application = '/path/to/application';
    
    • Controller defaults
      /**
       * The action method that should be called from your controller in case a
       * none-existant action is called (or none specified)
       */
      public $PHIBER_CONTROLLER_DEFAULT_METHOD = 'main';
      /**
       * The default controller to use if non is specified or not found
       */
      public $PHIBER_CONTROLLER_DEFAULT = 'index';

    Bootstrap

    bootstrap\start is not really a configuration file but because it is executed first it is a good place to put bootstrap code, add external libraries, register for events, start session or whatever checks and initialization tasks.

    Routes

    Phiber does NOT require any routes pre-configured to work. Instead the router uses convention to locate the target resources. Out of the box Phiber will route the following ugly URL:

    http://yoursite.com/<module>/<controller>/<action>/var1/val1?var2=val2/?var3/val3
    To:
    Array
    (
        [module] => dev
        [controller] => index
        [action] => action
        [vars] => Array
            (
                [var1] => val1
                [var2] => val2
                [var3] => val3
            )
    
    )
    
    And expects to find a controller class "index" and a function "<action>()" in the path
    modules/<module>/<controller>.php
    Of course that URL should not be what your links look like. This is a mere example of how flexible the URI parser in Phiber is. Phiber will guess which is a parameter name and which is the value using all "standard forms". Phiber promotes the same URI structure like Zend Framework using the slash ( / ) as a separator between params and their values.  This would result in a cleaner URL. The URL above would looke like this:
    http://yoursite.com/<module>/<controller>/<action>/var1/val1/var2/val2/var3/val3

    If you require configured routes however, Phiber provides two types that can be added right on the index.php file before calling Phiber::boot()
    • Simple routes (aliases):
      
    include "../vendor/phiber/phiber/library/phiber.php"; $phiber = new Phiber\wire('../application/config.php'); $phiber->addRoute(array('/info'=>'/module/controller/action/var1/val1');
    $phiber->addRoute(array('/about'=>'/module/controller/action/var1/val1');

    $phiber->boot();
    • RegEx and parameterized rules:
    $phiber->addRoute(array('~/info/(\d+)/(\d+)~'=>'/module/controller/action/:cat/:id'));
    This will match:
    /info/14/32
    And route it internally to:
    /module/controller/action/cat/14/id/32
    Both types support Closure to handle the requests.

    $phiber->addRoute(

    array('/info'=>

    function($phiberInstance) // an instance of Phiber is passed to your function automatically
    {
    // DB interactions
    $data = entity\myTable::getInstance()->select()->fetch();

    //Listen to an event

    Phiber\Event\eventful::attach(

    function($event)
    {

    var_dump($event);

    },

    Phiber\phiber::EVENT_SHUTDOWN
     
    );

    echo "some text"; // print something directly
    $phiberInstance->view->setLayout('path/to/layout.php'); $phiberInstance->view->setView('path/to/view.php');
    $phiberInstance->view->variable = 'assigned text';

    //Do a rewrite by setting a route and returning true

    $phiberInstance->currentRoute = array('module'=>'mod',
    'controller'=>'myController',
    'action' => 'myAction');

    //return (bool) true will tell Phiber to resume dispatching to a configured (or default) route
    return true;

      }
    );

    • Route Files
    These are php files holding many routes that can be grouped to keep your index.php file clean. To use one just create a php file put it anyware and then pass its path to the Phiber::addRoutesFile()
    //routes.php
    return array(
        array('~/info/(\d+)/(\d+)~'=>'/modeule/controller/action/:param1/:param2'),
        array('~/infos~'=>'/module/controller'),
        array('~/عربي/(\d+)/(\d+)~'=>'/myo/index/main/:cat/:id'),
        ...
        ...
        //Other routes
    );
    
    Then we can just pass it to Phiber
    $phiber->addRoutesFile('/path/to/routes.php');
    
    Install to a subfolder
    Phiber's default install expects to be in the root of your website where the index.php is the first to receieve any request coming to your website. To install in subfolders all you need is to edit two files the index.php and .htaccess (web.config for iis).
    //file: index.php

    //Make sure to update the include path for wire.php and config.php in this file

    //change <subfolder> to your folder name
    $phiber->baseUrl('<subfolder>');

    $phiber->boot()
    and
    //file: .htaccess 

    //change <subfolder> to your folder name
    RewriteRule ^.*$ /<subfolder>/index.php [NC,L]
    This configuration will allow you to use Phiber applications as such
    http://www.yoursite.com/<subfolder>/

    OOSQL

    The Object Oriented SQL interface is a lightweight Query Builder providing a fluent interface with ORM functionality.

    OOSQL's power stems from its use of the entity files created by the OOGen utility. This utility ships with the framework and can be used as a CLI script or using Myo through the entity command.

    Entity classes reflect the data model found in your database, capturing essential parts of your DDL to map the tables correctly. The entity class will hold the column names as properties. It also captures the primary key if there is any and in this regard it doesn't rely on any convention what so ever. Meaning, you could name your primary key whatever you like and not just id or user_id... etc.

    Entity classes will also understand your composite keys and give you ways to find records using all your key members or by one or more of them.

    Relationships (innoDB required) will be discovered and available to query against.

    Note: MySQL /MariaDB and PostegreSQL are the only databases supported up untill now.

    Step one

    Design your database like a DBA and make sure that your model is strong enough, use your favourite designer like MySQL Workbench then go ahead and create the physical database using a great DDL like this one:

     CREATE TABLE IF NOT EXISTS `employees` (
      `emp_no` int(11) NOT NULL,
      `birth_date` date NOT NULL,
      `first_name` varchar(14) NOT NULL,
      `last_name` varchar(16) NOT NULL,
      `gender` enum('M','F') NOT NULL,
      `hire_date` date NOT NULL,
      PRIMARY KEY (`emp_no`)
     ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     
    CREATE TABLE IF NOT EXISTS `salaries` ( `emp_no` int(11) NOT NULL, `salary` int(11) NOT NULL, `from_date` date NOT NULL, `to_date` date NOT NULL, PRIMARY KEY (`emp_no`,`from_date`), KEY `emp_no` (`emp_no`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    -- -- Contraintes -- ALTER TABLE `salaries` ADD CONSTRAINT `salaries_ibfk_1` FOREIGN KEY (`emp_no`) REFERENCES `employees` (`emp_no`) ON DELETE CASCADE;
    Step two
    The best way to do this is by using Myo but Phiber provides another way that can be accessed directly on CLI or programatically from your own code.

    The hard way
    Fire up a command line and cd to the oosql folder in the Phiber library, edit the generate.php file with your database credentials:
    <?php
    /**
    * Example entities generation script */

    // include 'pgsql.php';

     include 'mysql.php';
    //$gen = new Phiber\oosql\pgsql('pgsql:host=127.0.0.1;dbname=phiber', 'root', 'password');

     $gen = new Phiber\oosql\mysql('mysql:host=127.0.0.1;dbname=phiber', 'root', 'password');
    $gen->path = '/path/to/entityfolder';

     $gen->generate(); ?>
    And then execute it
    php generate.php
    

    The easy way
    A better option is to use Myo with the -g flag which will use your config directly so you won't edit anything (make sure you're in the application folder)
    myo entity -g
    
    In both scenarios you'll see something like this in your terminal:

    Attempting tables discovery... Analyzing employees physical columns ... Analyzing employees DDL ... Analyzing salaries physical columns ... Analyzing salaries DDL ... Found constraint salaries_ibfk_1 ... Generating class employees ... Done Generating class salaries ... Done Generated 2 classes in 0.0717 ms | Memory: 19.5859kb
     
    If you used Myo the generated files will be in the entity folder. Here's what they look like inside:
    /******************************
    * salaries.php */

    namespace entity; use Phiber; class salaries extends Phiber\entity\entity { public $emp_no; public $salary; public $from_date; public $to_date; public function getPrimary() { return array("emp_no","from_date"); } public function getPrimaryValue($key = null) { if(null === $key){ return $this->getCompositeValue(); } $pri = $this->getPrimary(); if(in_array($key,$pri)){ return $this->{$key}; } } public function getCompositeValue() { return array( "emp_no" => $this->emp_no, "from_date" => $this->from_date, ); } public function getRelations() { return array('emp_no'=>'employees.emp_no',); } public function belongsTo() { return array("employees"); } }
    /**********************************************************************
    * employees.php */
    namespace entity; use Phiber; class employees extends Phiber\entity\entity { public $emp_no; public $birth_date; public $first_name; public $last_name; public $gender; public $hire_date; public function getPrimary() { return array("emp_no"); } public function getPrimaryValue($key=null) { if(null === $key){ return array("emp_no" => $this->emp_no); } $pri = $this->getPrimary(); if(in_array($key,$pri)){ return $this->{$key}; } } public function hasMany() { return array("emp_no.salaries.emp_no"); } }

    What Entity classes are good for?
    Entity classes extend the entity class and automatically return an oosql\oosql instance giving you the possiblity to do whatever you need to do with the data in the table that coresponds to the class you called. They are accessible from anywhere (controllers, plugins, models ... etc). A natural place where to use those entity classes however is your model. A model will most likely do all the DB related work and is therefore a prime condidate for an example:
    <?php
    namespace model;
    use Phiber;
    
    class myModel extends Phiber\model
    {
    public function getEmployees()
    {
    return \entity\employees::getInstance()->select()->fetch();
    //Query: SELECT * FROM employees
    //Return: A collection of hiderated objects of the type entity\employees
    }
    }
    Pretty basic heh! This doesn't show the full potential of entities though. Still, the returned oosql\collection will give you more power and enable you to do a lot of things with the results without querying your DB:
     //Call our model
    $employees = model\myModel::getInstance()->getEmployees();

    //Search within the collection
    $oneEmployee = $employees->findOne('emp_no','10254');

    //Correct his name
    $oneEmployee->last_name = 'Doe'
    $oneEmployee->save(); // Will issue an update query with only the changed column

    //More search
    $femaleEmployees = $employess->findAll('gender','F');
    $countSmith = $employees->countWhere('last_name','smith');

    //We don't need male employees
    $employees->removeWhere('gender','M');


    //Lets iterate
    foreach($employees as $femaleEmployee){
    print $femaleEmployee->last_name. ' '. $femaleEmployee->first_name;
    }

    //Do we still have results?
    $empty = $employees->isEmpty();

    //Yes, how many?
    $num = $employees->count()

    //Lets sort'em
    $employees->sortByProperty('last_name');

    //Oh wait something happened we need our males back
    $employees->restoreWhere('geneder','M');

    //Last one
    $last = $employees->getLast();

    //Remove from the end
    $last = $employees->pop();

    //Free memory
    $employees->destroy();
    The hydrated objects still expose the oosql\oosql methods for you to manipulate data. The Query Builder is a straight forward mapper of the SQL DML commands.
    Check out all the methods exposed by oosql\oosql .

    Lazy or Eager?
    That depends on you. Both fetching modes are available through the oosql\oosql::with() and oosql\oosql::load() methods and a little MORE!
    The eager way
     $salaries = entity\salaries::getInstance()->select()
                  ->where('salary > ?',4400)                   
    // not specifying any columns will select employees.*
      ->with(array('employees' => array('last_name','first_name','gender')))
    ->limit(0,20)->fetch();

    $salaries->sortByProperty('salary','n'); //Numeric DESC
    $salary = $salaries->getLast()

    //Employees table related columns are immediately available
    $leastPaid = $salary->last_name .' '.$salary->first_name;

    The lazy way
     //Same query without a join
    $salaries
    = entity\salaries::getInstance()->select() ->where('salary > ?',4400) ->limit(0,20)->fetch();


    $salaries->sortByProperty('salary','n'); //Numeric DESC
    $salary = $salaries->getLast()

    //Employees table related columns are located upon request

    //by calling the related table as a method on the result object (Not the collection)

    $employee = $salary->employee();

    //
    Then loaded and made available (see why bellow)
    $employee->load()

    $leastPaid = $employee->last_name .' '.$employee->first_name;
    A little more
    After calling a related table in a lazy way the data is not loaded yet but we have the key value of the related row which allows us to manipulate the related row without loading its content i.e. without issuing any SELECTs.
    $employee = $salary->employee();
    $employee->last_name = 'Doe';
    $employee->save();

    //Zero SELECTs
    Another use for the Primary ID injection is in the insert operation too. Newly inserted records will recieve the last inserted ID (if it is an identity field) and will be returned by the save function itself so you can work with it without querying again (works for PostgreSQL too).
     $users = entity\users::getInstance();

    //Save new
    $users->first_name = 'Mohammed'; $users->last_name = 'Al Kacem';
     $user = $users->save();

    //Update newly saved record
    $user->last_name='Taha';
    $user->save();

    // Zero SELECTs
    Models
    This is an important concept of the MVC pattern. Your model holds your domain logic, your data structure and manipulation routines. It doesn't have to do a database related task for your model to provide data and domain logic for your application. That's why the model class in Phiber will not inherit any database related routines to give you a lightweight sane launch pad. Database mapping is not done in your models but in your entity files instead allowing you to split the fat and keep your models as clean as possible.
    Create models manually in the model directory or by using Myo. An example model file would look like this:


    namespace model; use Phiber\model; class mymodel extends model {
    public function getData()
    {
    /* Your code here */
    }
    }
    To use this model just call an instance of it.
    $data = model\mymodel::getInstance()->getData();

    The V in the middle

    Can models talk to views?
    Yes, they can. The MVC term is used so much all over the web and is implemented as a pattern by different frameworks. The original architecture however, is not being respected by all frameworks. Instead, variants of this architechture are in use and even Phiber does not follow the orginal MVC architecture to the letter.
    But Phiber does respect one of the features of the MVC architecture which is the ability for models to communicate with views. Models in a Phiber application can create view variables that can be rendred directly by the view.

    class mymodel extends model
    {
    public function getData()
    {
    $this->view->someVar = "from model";
    }
    }

    // In your view file

    echo $this->someVar;
    If the data returned by the model doesn't need any more processing by the controller (errors and failures, dumb lists or other notifications) there is no need to assign that variable within the controller. This trick will put the V back in the middle and help you make your models fatter.

    Plugins
    Plugins are parts of your application that are executed (or called) every time your application initializes. Each time your application receives a request Phiber will load and execute every plugin you declared. Plugins are executed after routing but before dispatching the request. In simple English Phiber executes the plugins after deciding which module, controller and action should be executed but before they are actually executed. This gives you the ability to access and/or controll every aspect of your application and alter or enhance its behaviour at will. Your authentication and any authorization system for example should be implemented as a plugin so you can make sure that every access request is checked.
    A plugin is a folder containing all the code you need and provides an entry point for Phiber to execute it. The entry point is a php file with your plugin name extending Phiber\plugin and implementing run() method. This method is your plugin's execution point (much like main() in C or Java).
    Here's an exmple of an authentication/authorization plugin
    /path/to/myapp/application/plugins/auth/auth.php
    
    class auth extends \Phiber\plugin
    {
    
      private $user = null;
      private $resource = null;
    
      public function __construct()
      {
        //Get the requested module
        $this->resource = $this->route['module'];
    
      }
      public function run ()
      {
       
    //What modules that don't need authentication $allowed = array("default","auth","about");

    //Get user info from the session (guest user is there by default)
     $this->user = $this->session->get('user'); if(($this->user['name'] === 'guest') && !in_array($this->resource,$allowed)){ $this->_redirect('/auth/login');

     return;

     }else{
    //If we're here
     //This is a logged in user or a publically accessible resource

     if($this->user['name'] != 'guest'){

    /* User is logged in */

      } } } }
    Check Phiber\plugin API documentation for a list of all available methods and properties.

    Modules
    The building blocks of your application and the primary unit for its features. The modules are controllers grouped together in folders. A module like a plugin doesn't need any configuration just drop it in the modules folder and it should be functional.
    The basic unit in this architecture is the controller. So, you'll need at least one controller in a module for it to be of any use. You can create modules by creating folders and droping a controller in it within the modules folder.
    /path/to/myapp/application/modules/books/catalog.php
    Where "books" is the module name and catalog.php is the controller.
    class catalog extends Phiber\controller
    {
      public function main()
      {
        $this->view->books = model\books::getInstance()->list();
      }
    }
    Modules also house the views for the controllers within.
    /path/to/myapp/application/modules/books/views/catalog/main.php
    
    The catalog folder within the views holds all the partial views related to that controller.
     <?php
    foreach($this->books as $book){
    echo $book->title;
    }

    See Myo for a better way to maintain your modules.

    Events
    Phiber provides a way to trigger and listen to events using the eventful class or by implementing the appropriate interfaces to further customize the way events are handled. A class must expose the events that could be expected from it to become "eventful". Event names are namespaced to avoid collision and to provide an easy way to organize them. For example the built-in session class fires two events one for session regenration and the other for session destruction.
    //You don't have to prefix event constants with the word 'EVENT' 
    //Pick a name that you like (you'll use it later for getEvents())

    const EVENT_REGEN = 'session.regenerate';
    const EVENT_DESTR = 'session.destroy';
    An event object holds some information about the event (event object is itself a bag object that could hold anything you want). Namely, the event name and the authority that fired the event. Authority could be the name of the firing method, class, interface, module or anything really. It provides a way to help identify the source of your event in case the same event name can be fired from different places within your application.
        $authority = __METHOD__;
    
        $event = new Phiber\Event\event(self::EVENT_DESTR,  $authority);
    The eventful class exposes also two methods.
    public static function attach($observer, $event, $hash = null, $m = null)
    Using attach() one can attach a listener object to one or all the events fired by session.
    Phiber\Event\eventful::attach($observer, Phiber\Session\session::EVENT_DESTR);
    Or register to all the events by specifying the root part of the event name.
    Phiber\Event\event::attach($observer, 'session');
    The other function is used to undo the previous one and unregister our observer
    public static function detach($observer = null, $event,$hash = null)
     detach() is used in a similar fashion where providing an already registered observer name with an event will unregister that observer and will no longer respond to that event:
    Phiber\Event\eventful::detach($observer, Phiber\Session\session::EVENT_DESTR);
    If you want to unregister from all events fired by session just provide the root part of the event
    Phiber\Event\eventful::detach($observer, 'session');
    The class session in this case must define the method
    public static function getEvents(){}
    This method is used by eventful::attach() and eventful::detach() to determine what events are available. It must return an array with the available events.
    Defined in session like this:
    public static function getEvents()
      {
        return array(self::EVENT_DESTR,self::EVENT_REGEN);
      }
    Fire an event
    To fire an event all we need is to call notify(). This method takes our event object as a parameter.
    Phiber\Event\eventful::notify($event);

    A listner or an observer is an object that has an update() method (it could implement phiberEventObserver or extend Phiber\Events\listener or not) you could just define the method in your class as such.
    public function update(Phiber\Event\event $event){}
    The update method will be executed each time an event that you registered for is fired.
    An Example
    Let's create a dummy library with a dummy listener
    // application/lib/event/listen.php

    <?php namespace event; use Phiber\Event; class listen extends Event\listener { public function update(Event\event $event) { var_dump($event); } }
    Now we'll create a plugin (it could be done in a controller or a model too)

    <?php
    use Phiber\Session\session;

    class examplePlugin extends Phiber\plugin { public function run() { //Register our dummy library (see External Libraries in this doc)

    $this->addLib('event');

    //Attach our listener to the session
     
    Phiber\Event\eventful::attach('event\listen', session::EVENT_REGEN); } }
    Now, every time the session regenerates event\listen::update() will execute.
    Another good place to declare your listeners is bootstrap\start This file/class will be run before anything else and is a good place to put any boostrap code. Events that should listen to 'phiber.boot' for example should definitely be decalred in this file or they'll never be called (because that event fires before calling other parts of the application).
    Attach a closure
    Closures are a quick way to listen for events and act on them. They can be attached the same way other objects are and an Event object is passed to them as a parameter.
     Phiber\Event\eventful::attach(  function($event)
    {
    var_dump($event);

    }, Phiber\phiber::EVENT_SHUTDOWN
     
    );
    The example above is the simplest way you can use Closures with events but if you want to be able to dettach them later in runtime you'll need to provide a hash to identify them. A hash can be any random string.
      $hash = sha1('myshutdownclosureIdStr')
     
    Phiber\Event\eventful::attach(

    function($event)
    {

    var_dump($event);

    },

    Phiber\phiber::EVENT_SHUTDOWN, $hash
     
    );

    // You can use the same hash later to detach this listener
    Phiber\Event\eventful::detach(null, Phiber\phiber::EVENT_SHUTDOWN, $hash);
    Custom method
    The default method called on listener objects is update() but you can easily overide this behaviour by providing your own method name to the attach() method.
    Phiber\Event\eventful::attach($observer, Phiber\phiber::EVENT_SHUTDOWN, null, 'myMethod'); 
    This way everytime 'phiber.shutdown' is fired $observer->myMethod(event $event) will execute.
    Syntactic sugar
    Controllers, Models and Plugins provide easier ways to register for events through the attach() builtin method. This method is different than the one provided by eventful.

     protected function attach($event, $observer = null, $hash = null, $runMethod = null)
    Use it like this:
     //Plugin, Model or Controller
    $this->attach(Phiber\phiber::EVENT_SHUTDOWN);

    //this will hold a copy of this object and execute update() on it when event is fired
    To register a different method to execute on event pass its name as the fourth param.
    //Plugin, Model or Controller
    $this->attach(Phiber\phiber::EVENT_SHUTDOWN, null, null, 'myMethod');
    To pass in a different object instead of the current Plugin, Model or Controller instance pass this object (or class name) as the second parameter
     $observer = new library\myClass();
    //or
    $observer = 'library\\myclass'; //It'll be instanciated on event

    $this->attach(Phiber\phiber::EVENT_SHUTDOWN, $observer, null, 'myMethod');
    The event name can be also passed directly instead of using the constant (not recommended)
     $this->attach('phiber.shutdown');
    //same as
    $this->attach(Phiber\phiber::EVENT_SHUTDOWN);
    Firing an event from a Plugin, a Model or a controller as you might expect now is just as easy.
    $event = new Phiber\Event\event('mypackage.myevent',__class__);

    $this->notify($event);
    Layout & views
    Since PHP itself is an excellent templating langugae Phiber doesn't waste any effort/resources parsing a template language of its own but you can use one if want to. (see using external libraries in this doc). Actually Phiber allows you to use more than one templating engine at the same time if you feel the need to.
    A layout is the main template file and all other partial templates (views) are merged into it before outputing. The layout file should be within the layouts folder of the application but the file name is configurable in your configuration file (defaults to layout.php).
      /**
       * Layout file
       */
      public  $PHIBER_LAYOUT_FILE = 'layout.php';
    A layout file should call the render() method where the partial view should be rendered.
    $this->render();
    View files are associated with actions and are partial template files that will define formating for data specific to the action that called it. To escape-print a variable in a partial template or in the main layout file Phiber provides the T_() function.
    T_($this->var);
    // a wrapper for
    echo htmlentities($this->var);
    Text, objects and arrays (or any other data/resource) can be passed to your views from your controllers, plugins or models by assigning them to the View object available to all of them at runtime. (Make sure to use unique names for your variable names to avoid overriding them).
    //Controllers, Plugins or Models

    $this->view->variable = 'value';
    //or array
    $this->view->array = array('someValue');
    //or object
    $this->view->obj = new stdClass;
    Variables created like this can then be output to your users from within your temple files (partial and layouts).
    <h3><?php T_($this->variable) ?></h3>

    <table id="cart">
    <?php
    foreach($this->array as $columns){
    echo '<tr><td>'
    echo implode('</td><td>',$columns);
    echo '</td></tr>';
    }
    ?>

    </table>

    <span id="total"><?= $this->obj->total ?></span>
    View files are expected within the view directory within each module. There is a folder for each controller and a view file for each action within that controller.
    /path/to/myapp/application/modules/<module>/views/<controller>/<action>.php
    Cache
    For expensive data fetching operations choosing a good cache mechanism and implementing it correctly is crucial to your application. The problem I've seen with some cache implementations is the complex configuration. Phiber provides an easier way for your cache needs. The only available driver untill now though is the file based caching. Don't panic not only that you can create your own cache solutions and use them very easily but you can also use composer to install and use your favourite cache library (see external libraries in this doc).

    $driver = new Phiber\Cache\file;
    $cache = new Phiber\Cache\cachepool($driver);

    $key = sha1('employees');

    $data = $cache->getItem($key);

    if($cache->isHit()){ // Do we have a valid cahced version
    $employees = $data; // use it
    }else{
    // No cache was found lets hit the DB

    $employees = entity\employees::getInstance()->select()->fetch(1000);
    $cache->save($key,$employees,60); //Cache data for one minute

     }
    The Phiber\Cache\cachepool class will be used always to deal with your cache regardless of your backend. Except for the driver, the code above can be used with a NoSQL backend, Memcache or any other facility you have deployed for cache purposes. The Phiber\Interfaces\cacheDriver interface defines a common interface for your driver implementations (see the file driver implementation as an example).
    namespace Phiber\Interfaces;
    
    interface cacheDriver
    {
      public function set($key,$value,$ttl = null);
      public function getKey();
      public function get($key);
      public function getBag();
      public function getMulti($keys);
      public function deleteAll();
      public function delete($key);
      public function isHit();
      public function exists($key);
      public function setExpiration($ttl = null);
      public function getExpiration();
    }
    
    Bag items
    Each object sent to be cached should be wrapped into an item object first that would serve as a bag for it, holding some information about it. This bag object provides a way for the driver to evaluate/update/get/set the ttl and timestamp of the object while the data is untouched which also would save us any filesystem acrobacies. The item class is very simple and its usage is easy too.
    namespace Phiber\cache;
    
    class item
    {
      public $data,
             $ttl,
             $timestamp;
    
      public function setTtl($ttl)
      {
        $this->ttl = (int) $ttl;
        $this->timestamp = microtime(true);
      }
    
    }
    You probably already guessed how we are going to use this bag within our driver.
      $this->bag = new Phiber\Cache\item();
      $this->bag->data = $object; // The object to cache
      $this->bag->setTtl($ttl); // ttl in seconds
    Log
              "Programming is the art of creating errors"
                                                                               ~~ A wise man said once

    Logging and error reporting is probably the most important part of software development and not only while developing but also in maintenance. Phiber gave great care to this part. The error handler provided by Phiber integrates with your application and converts every error to an Exception. Phiber catches even Fatal Errors and uses an intuitive way to log/display those errors. Phiber by default will display any error to your screen in debug mode (logs them too). Other log modes are more suitable for production since they don't display anything to your browser. The log will ignore all modes bellow the selected mode. If you want to ignore Notice messages (not recommended) you can chose warning mode. Phiber however will log everything above the chosen mode. A log mode warning will also log any event marked as error, critical, alert or emergency.
    All errors provided natively by PHP are handled and categorized into one of the seven levels provided.
        // Fatal Error [emergency]
    E_ERROR E_COMPILE_ERROR E_CORE_ERROR E_PARSE E_USER_ERROR

    // Uknown error [alert]

    // Warning [critical]
    E_COMPILE_WARNING E_CORE_WARNING E_WARNING

    // Catchable [error]
    E_RECOVERABLE_ERROR


    // User Warning [warning]
    E_USER_WARNING
    // Notice [notice]
    E_USER_NOTICE E_NOTICE E_STRICT

    // Deprecated [info]
    E_DEPRECATED E_USER_DEPRECATED

    Converting all errors to an Exception means that you can catch PHP error or user triggered errors in a try catch block. (in debug mode a stacktrace will be printed for this type of errors, E_USER_WARNING won't print a stacktrace)
     try {
    trigger_error('Something bad happened!',E_USER_ERROR) }catch(\Exception $e){
    echo $e->getMessage();
    }

    //Without a try catch you'll never get here
    echo 'This part will be printed just fine Now.';
    Phiber provides also a way to change the behaviour on warnings i.e. just log the warning and go on with our lives or halt and let somebody know they messed up (see the configuration section above).

    Log handlers

    Phiber ships with only the file log handler (log to files) but provides an abstract logger class for you if you want to log to other mediums (syslog, remote log, email ... etc).
    Another log handler could be easily added using the wire::setLog() method.
    public function setLog($logger = null,$params = null,$name = null)
    This method defaults to whatever you spcified in your configuration (file in this case). The second parameter is just an array of options passed to the constructor of your log handler (log file path in this case) and could be anything your handler needs. The last param is a name that would be used to index your handler within a stack of handlers if you use more than one. This is an extendable multi channel log facility that you can use whichever you please. For file log handler you can also use more than one log file, to log different events to different files for example.

    $this->setLog(null, 'secondlog','mylog'); // since 'file' is default null is enough

    $this->setLog('file', 'anotherlog'); // log index name will be used as filename

    //Suppose that you created an email based log handler
    $this->setLog('email', 'myemail@domain.com','myemail');

    //Use them

    $this->logger()->info('Log an info event')// log to default logfile

    $this->logger('mylog')->notice('Log a notice event');// log to logs/secondlog.log

    $this->logger('anotherlog')->error('Log an error event');// log to logs/anotherlog.log

    $this->logger('myemail')->alert('Log an alert event'); // sends and email
    WTF
    That's probably the word that springs to your had (sometimes makes it to your lips) whenever you see something you didn't expect your application to do. I've seen this on Aaron Fisher's blog and couldn't stop using it since then (the version I ended up using is slightly different though).
    If you want to pretty print an object to see what is going on in an eyes-friendly manner and without truncated data (var_dump and print_r are ugly) just pass that object to this static function provided by Phiber\tools.
    Phiber\tools::wtf($object);
    Phiber uses this in debug mode to pretty print and format stacktraces and error messages.

    External libraries
    The motivation behind the creation of Phiber is well supported by the lack of a really light weight, easy to learn and performing framework for PHP. I have no intention to reinvent the wheel though (that's why Phiber ships with bare minimum handlers for cache and log for example). There exists some great libraries out there to handle specific tasks and we have an excellent dependency manager (composer). One of the greatest things about Phiber is that it'll let you use any library in a very convenient way. Composer autoloader can be used directly to load your libraries. Just uncomment that line the requires the composer's autoloader in index.php.
    //require "../vendor/autoload.php";
    That's all you need to do to use Twig for example. Twig is a powerfull albeit heavy templating engine that is designer friendly. To use it just require it in your composer.json, run the update command and then use it right away on your Phiber application.
    One way to do this (we'll be using Twig along with Phiber's templating) is by creating a templates folder within your application and then  initializing Twig in the bootstrap\start as such:
    //file: /path/to/myapp/application/bootstrap/start.php

    $loader = new \Twig_Loader_Filesystem($wire->config->application.'/templates/'); $twig = new \Twig_Environment($loader,array( 'cache' => $wire->config->application.'/data/cache', ));
    // pass it to the rest of the framework $wire->twig = $twig;
    Now all you need is to actually create your templates and use them
    //file: /path/to/myapp/application/templates/mytemplate.tpl

    {{name}} {{type}}
    Within your controller prepare your template
    //file: /path/to/myapp/application/modules/<module>/<controller>.php

    $this->view->name = 'Phiber';
    $this->view->type = 'Framework';
    $this->view->template = $this->twig->loadTemplate('mytemplate.tpl');
    All is left now is to use that temple in our partial view
    //file: /path/to/myapp/application/modules/<module>/views/<controller>/<action>.php

    echo $this->template->render(array('name' => $this->name, 'type' => $this->type));
    If you want to use only Twig templating just disable the layout (in configuration or dynamically in runtime) along with views in the bootstrap\start script.
    //file: /path/to/myapp/application/bootstrap/start.php

    $wire->view->disableLayout(); // not needed if disabled in configuration $wire->view->disableView();

    What if I don't use composer?

    No problem (consider using composer if you can though)
    Phiber provides another way to register external libraries to be used within your application.
    All you need to do is to drop your library in the lib folder within your application then, within a plugin or the bootstrap\start script (can be done within a controller or a model too) call the addLib() method and register the root namespace of your library. For example the Browser\Browser library could be loaded this way.
     $this->addLib('Browser','gabrielbull/browser/src/Browser');
    Phiber will only load correctly namespaced libraries (correctly means in relation to the filesystem hirarchy here).
    Now you can just use this library like so:
    $browser = new Browser\Browser;

    Myo
    Myo is a command line tool designed specifically to save you few brain cells when dealing with the most boring (yet very important) parts of the life of a developer. This includes creating folders and files and laying out the hirarchy for the application. Not just any folders or files we're talking creating modules, controllers, views, plugins, extensions and generating entity files of huge databases holding hundreds of tables in FEW seconds!
    Yes, you got that right, just read on.
    Requirements
    - php5-curl
    - libcurl4-openssl-dev
    - Zip
    How to use Myo?
    Installing Myo is as easy as unzipping the archive you downloaded anywhere on your dev machine (or cloning it from github). You'll need to have php in your path and, depending on your operating system, you need to use the myo.bat or myo. Add Myo's installation directory to your path.
    Myo might look for the config.php file in the working directory. To work on an application just cd to its application folder.
    >cd /path/to/myapp/application
    Another way to it is to provide your application configuration path as an option to Myo on each command.
    >myo <command> --conf-path /path/to/myapp/application/config.php
    Not all commands require the configuration file though.

    A Phiber Application
    An application for Phiber is a set of components grouped together in a folder called application.
    The application folder is where you'll spend the most of your time creating modules, controllers, views, plugins, entities, models, layouts and routes. It also has a logs folder to check your logs and houses the config.php file where all your settings are.
    Creating and maintaining a hirarchy of folders and files might turn quickly into an unmanageable mess after few weeks of work. It's even harder to come back after sometime to work on an old project or WORSE working on somebody's else code.
    With Myo however, maintaining your MVC layout will not be intimidating no more.

    Create an application
    Creating an application with Myo involves unpacking a sample application that is included with Myo with an option to fetch the latest sample application straight from github for you.

    >myo app myapp

    The current version is: t548c6cb28911d7dce5d96e645c856a7b35dabf Do you want to check the HEAD revision on Github [no]?(yes/no)
    If you chose to check for updates you'll be asked to provide your github credentials to query their API for updates. Enter your username and hit Enter.
    Your github username:<type your username>
    For extra security, in case you're not alone or just paranoid, the password will not show up when typing (Windows and Linux). Just type it in and hit Enter.
    If the HEAD revision is newer you'll get something like this :
    Fetching revision: g5475ff2f44a9102d8b78639bfcc221c110390b3
    
    Done!
    
    Deploying g5475ff2f44a9102d8b78639bfcc221c110390b3 ...
    
    To: /path/to/myapp
    
    Unpacking ...
    
    Would you like to configure myapp [yes]? (yes/no)
    If your version is already up-to-date
    You seem to have the latest version!
    
    Deploying g5475ff2f44a9102d8b78639bfcc221c110390b3 ...
    
    To: /path/to/myapp
    
    Unpacking ...
    
    Would you like to configure myapp [yes]? (yes/no)
    If you chose "no" at this stage you're done. Go to your config.php put in DB credentials and path information and then go to the next step.
    If your answer was "yes" however, Myo will ask for some more information
    Host [mysql]: localhost
    
    DB Name [mysql]: myapp_db
    
    DB User [mysql]: db_user
    
    DB Passwrod [mysql]:
    Your path information will be populated automatically as well. All you need now is to add Phiber to the mix.
    cd myapp
    composer self-update
    composer install
    That's it, if you set up a vhost or change your docroot to the newly created
    /path/to/myapp/public_html
    You'll be reading this document from a fresh install of a sample Phiber application. Congrats!

    Create a module
    A module for Phiber is a standalone part of your application holding a group of controllers.
    For Myo a module is a folder with at least one file (controller) and two folders. The views folder within any module comprises a folder for each controller (named after it) where the partial views corresponding to the controller's actions are stored.
    How to create a module with Myo then?
    Myo's command mvc exposes the options you need to create different parts of your MVC layout.
    //Don't forget to cd to the application folder

    >myo mvc --module books
    The command above will create a folder structure like this
    /path/to/myapp/application/modules/books/views/<default controller>
    The books folder will have a default controller (its name depends on your config). The views folder will have a folder with the name of the default controller. Within that folder a partial view file will be created with the name of the default action (also in your config).
    /path/to/myapp/application/modules/books/views/<default controller>/<default action>.php
    With default settings the path will look something like
    /path/to/myapp/application/modules/books/views/index/main.php
    "index" is the default controller and "main" is the default action.

    Create controllers
    In the same fashion, creating a controller is only one command away.
    >myo mvc --module books --controller catalog
    The command above will create controller catalog within the module books. If we hadn't create the module "books" this command would have done that without adding the default controller this time. The created files and folders are:
    /path/to/myapp/application/modules/books/catalog.php
    And
    /path/to/myapp/application/modules/books/views/catalog/main.php

    Create actions
    To create an action we'll need to specifiy both the module name and the controller name. If they don't exist they'll be created for us.
    >myo mvc --module books --controller catalog --action show
    This will add a method to the class catalog in the catalog.php file
    class catalog extends Phiber\controller
    {
      public function main()
      {
        /* Default action */
      }
    public function show()
    {
    /* Action code here */
    }
     }
    And a view file called show.php within the views folder.
    /path/to/myapp/application/modules/books/views/catalog/show.php

    Create models
    Models can also be created by this same command.
    >myo mvc --model mymodel
    The newly created model will be empty.
    /**
    * /path/to/myapp/application/model/mymodel.php
    */
    <?php namespace model; use Phiber\model; class mymodel extends model {
    }

    Create entity
    Generate entity files using this command to map your tables automatically using classes. Entity files are tightly linked to your database. Please check the OOSQL entry above if you didn't do that already.
     	
    _ __ ___ _ _ ___ | \'_` _ \| | | |/ _ \ | | | | | | |_| | (_) | |_| |_| |_|\__, |\___/ __/ | |___/ Phiber's Command Line Tool <version>
    Author: Housseyn Guettaf <ghoucine@gmail.com>

    Usage: myo <comand> <flag> [[--option1 value][--option2 = value]...] -- arg1 arg2 ... Flags: -i Preserve case otherwise files will always be created in lowercase -g Generate entity files when used with myo entity Commands: app Creates a new Phiber application Usage: myo app <appname> Options: --app-path Specify the application path entity Creates an entity file or generate entities from db with -g Usage: myo entity <entity name> Creates an empty entity file myo entity -g Generates entity files from the database with no options it will use your config to access the db and put the files into the entity folder options: --db-dsn The dsn of your db --db-host Database host --db-name Database name, overides --db-dsn --db-user Database username --db-pass Database password --entity-path The folder to put generated files in ext Creates myo extensions. Usage: myo ext <extension name> The new extension will be used as a command: myo <extension name> help Provides more information about commands. Usage: myo help <command> mvc Creates different parts of the MVC layout. mvc <flag> [option] Options: --module <module name> Creates a module and defaults to module 'default' --controller <controller name> Creates a controller and defaults to 'index' --model <model name> Creates a model --action <action name> Creates an action for a given controller

Found a typo? Want to correct something? Please fork this doc and send a pull request