Tired of plain PHP or from using your old bloated and messy framework?
Phiber Framework is free for personal and commercial projects. Phiber Framework is released under the terms of the MIT license.
composer create-project phiber/sample-app your-project-name
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]
try_files $uri $uri/ /index.php?$args;
The configuration file doesn't have to be called config.php
$phiber = new Phiber\wire('../application/config.php');
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';
If you use Myo to install the application
public $PHIBER_DB_DSN = 'mysql:host=127.0.0.1;dbname=databaseName';
public $PHIBER_DB_USER = "root";
public $PHIBER_DB_PASS = "password";
myo app myappAfter 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.
/** * 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 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;
/** * 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';
/** * 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\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.
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/val3To:
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>.phpOf 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
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();
$phiber->addRoute(array('~/info/(\d+)/(\d+)~'=>'/module/controller/action/:cat/:id'));This will match:
/info/14/32And route it internally to:
/module/controller/action/cat/14/id/32Both 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;
}
);
//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
//file: index.phpand
//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()
//file: .htaccessThis configuration will allow you to use Phiber applications as such
//change <subfolder> to your folder name
RewriteRule ^.*$ /<subfolder>/index.php [NC,L]
http://www.yoursite.com/<subfolder>/
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;Step two
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;
<?php /**And then execute it
* 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(); ?>
php generate.php
-g
flag which will use your config directly so you won't edit anything
(make sure you're in the application folder)myo entity -gIn both scenarios you'll see something like this in your terminal:
If you used Myo the generated files will be in the entity folder. Here's what they look like inside:
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
/******************************
* 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"); } }
<?php namespace model; use Phiber; class myModel extends Phiber\model {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:
public function getEmployees()
{
return \entity\employees::getInstance()->select()->fetch();
//Query: SELECT * FROM employees
//Return: A collection of hiderated objects of the type entity\employees
}
}
//Call our modelThe 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.
$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();
$salaries = entity\salaries::getInstance()->select() ->where('salary > ?',4400)The lazy way
// 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;
//Same query without a joinA little more
$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;
$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();Models
//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
To use this model just call an instance of it.
namespace model; use Phiber\model; class mymodel extends model {
public function getData()
{
/* Your code here */
}
}
$data = model\mymodel::getInstance()->getData();
class mymodel extends model {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.
public function getData()
{
$this->view->someVar = "from model";
}
}
// In your view file
echo $this->someVar;
/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./path/to/myapp/application/modules/books/catalog.phpWhere "books" is the module name and catalog.php is the controller.
class catalog extends Phiber\controllerModules also house the views for the controllers within.
{
public function main()
{
$this->view->books = model\books::getInstance()->list();
}
}
/path/to/myapp/application/modules/books/views/catalog/main.phpThe catalog folder within the views holds all the partial views related to that controller.
<?php
foreach($this->books as $book){
echo $book->title;
}
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'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.
//Pick a name that you like (you'll use it later for getEvents())
const EVENT_REGEN = 'session.regenerate';
const EVENT_DESTR = 'session.destroy';
$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 methodpublic 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. session
like this:public static function getEvents() { return array(self::EVENT_DESTR,self::EVENT_REGEN); }
Fire an eventnotify()
. This
method takes our event object as a parameter.Phiber\Event\eventful::notify($event);
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.// application/lib/event/listen.phpNow we'll create a plugin (it could be done in a controller or a model too)
<?php namespace event; use Phiber\Event; class listen extends Event\listener { public function update(Event\event $event) { var_dump($event); } }
<?php use Phiber\Session\session;Now, every time the session regenerates
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); } }
event\listen::update()
will execute.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).Phiber\Event\eventful::attach( function($event)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.
{
var_dump($event);
}, Phiber\phiber::EVENT_SHUTDOWN
);
$hash = sha1('myshutdownclosureIdStr')Custom method
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);
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.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 ControllerTo register a different method to execute on event pass its name as the fourth param.
$this->attach(Phiber\phiber::EVENT_SHUTDOWN);
//this will hold a copy of this object and execute update() on it when event is fired
//Plugin, Model or ControllerTo pass in a different object instead of the current Plugin, Model or Controller instance pass this object (or class name) as the second parameter
$this->attach(Phiber\phiber::EVENT_SHUTDOWN, null, null, 'myMethod');
$observer = new library\myClass();The event name can be also passed directly instead of using the constant (not recommended)
//or
$observer = 'library\\myclass'; //It'll be instanciated on event
$this->attach(Phiber\phiber::EVENT_SHUTDOWN, $observer, null, 'myMethod');
$this->attach('phiber.shutdown');Firing an event from a Plugin, a Model or a controller as you might expect now is just as easy.
//same as
$this->attach(Phiber\phiber::EVENT_SHUTDOWN);
$event = new Phiber\Event\event('mypackage.myevent',__class__);Layout & views
$this->notify($event);
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);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).
// a wrapper for
echo htmlentities($this->var);
//Controllers, Plugins or ModelsVariables created like this can then be output to your users from within your temple files (partial and layouts).
$this->view->variable = 'value';
//or array
$this->view->array = array('someValue');
//or object
$this->view->obj = new stdClass;
<h3><?php T_($this->variable) ?></h3>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.
<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>
/path/to/myapp/application/modules/<module>/views/<controller>/<action>.phpCache
The
$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
}
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
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 secondsLog
"Programming
is the art of creating errors"
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
.// Fatal Error [emergency]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_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
E_USER_WARNING
won't print a stacktrace)try {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).
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.';
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.
WTF
$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
Phiber\tools
.Phiber\tools::wtf($object);Phiber uses this in debug mode to pretty print and format stacktraces and error messages.
//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.
//file: /path/to/myapp/application/bootstrap/start.phpNow all you need is to actually create your templates and use them
$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;
//file: /path/to/myapp/application/templates/mytemplate.tplWithin your controller prepare your template
{{name}} {{type}}
//file: /path/to/myapp/application/modules/<module>/<controller>.phpAll is left now is to use that temple in our partial view
$this->view->name = 'Phiber';
$this->view->type = 'Framework';
$this->view->template = $this->twig->loadTemplate('mytemplate.tpl');
//file: /path/to/myapp/application/modules/<module>/views/<controller>/<action>.phpIf you want to use only Twig templating just disable the layout (in configuration or dynamically in runtime) along with views in the
echo $this->template->render(array('name' => $this->name, 'type' => $this->type));
bootstrap\start
script.//file: /path/to/myapp/application/bootstrap/start.php
$wire->view->disableLayout(); // not needed if disabled in configuration $wire->view->disableView();
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).
$browser = new Browser\Browser;
>cd /path/to/myapp/applicationAnother 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.phpNot all commands require the configuration file though.
>myo app myappIf 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.
The current version is: t548c6cb28911d7dce5d96e645c856a7b35dabf Do you want to check the HEAD revision on Github [no]?(yes/no)
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.
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.
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 myappThat's it, if you set up a vhost or change your docroot to the newly created
composer self-update
composer install
/path/to/myapp/public_htmlYou'll be reading this document from a fresh install of a sample Phiber application. Congrats!
//Don't forget to cd to the application folderThe command above will create a folder structure like this
>myo mvc --module books
/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>.phpWith 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.
>myo mvc --module books --controller catalogThe 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.phpAnd
/path/to/myapp/application/modules/books/views/catalog/main.php
>myo mvc --module books --controller catalog --action showThis will add a method to the class catalog in the catalog.php file
class catalog extends Phiber\controller { public function main() { /* Default action */ }And a view file called show.php within the views folder.
public function show()
{
/* Action code here */
}
}
/path/to/myapp/application/modules/books/views/catalog/show.php
>myo mvc --model mymodelThe newly created model will be empty.
/**
* /path/to/myapp/application/model/mymodel.php
*/
<?php namespace model; use Phiber\model; class mymodel extends model {
}
_ __ ___ _ _ ___ | \'_` _ \| | | |/ _ \ | | | | | | |_| | (_) | |_| |_| |_|\__, |\___/ __/ | |___/ 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