Your SlideShare is downloading. ×
0
How to learn to build  your own PHP framework Bridging the gap between PHP, OOP and Software Architecture Pham Cong Dinh (...
Introduction <ul><li>A foundation member of JavaVietnam since 2003 ( http://www.javavietnam.org ) </li></ul><ul><li>A foun...
Objectives <ul><li>Where is PHP now? It is changing. </li></ul><ul><ul><li>Enterprise oriented: which is driven by Yahoo, ...
Agenda – 40 slides <ul><li>Making judgments </li></ul><ul><li>Top notch frameworks and their shortcomings </li></ul><ul><l...
Making judgments <ul><li>Common wisdom: Reinventing the wheel </li></ul><ul><li>Good </li></ul><ul><ul><li>You know it ins...
Making judgments <ul><li>To develop a framework is just like to set up a business </li></ul><ul><li>Think of your limitati...
Know the market <ul><li>CakePHP shortcomings </li></ul><ul><li>Zend Framework shortcomings </li></ul><ul><li>Third party f...
Know the market - CakePHP <ul><li>Misleading terms: plugin, model…  </li></ul><ul><ul><li>Plugin: CakePHP allows you to se...
Know the market - CakePHP <ul><li>No elegant way to change media file (css, javascript, meta content) on each layout page,...
Know the market - CakePHP <ul><li>loadModel(), loadController() are not about dependency injection </li></ul><ul><li>E.x: ...
Know the market - CakePHP <ul><li>beforeFilter(), afterFilter() are coupled with a certain controller (controller is a hea...
Know the market - CakePHP <ul><li>Reuse of view via elements with  requestAction()  is bad and expensive </li></ul><ul><ul...
Know the market - CakePHP <ul><li>Caching hits its hard time because there is no way to get generated view content </li></...
Know the market – Zend Framework <ul><li>Zend Framework tries to be a better PEAR </li></ul><ul><ul><li>Powered by a solid...
Know the market – Zend Framework <ul><li>Zend Framework is extremely big and bloated </li></ul><ul><ul><li>Zend Framework ...
 
Know the market – Zend Framework <ul><li>Everything is an object, even a HTML button or checkbox. The same to Java (see Ap...
Know the market – Zend Framework <ul><li>What Zend Framework brings </li></ul><ul><ul><li>Lot of files are loaded per requ...
Know the market – Zend Framework <ul><li>A glue framework requires you to know every concrete class and how to use them in...
Know the market – Zend Framework <ul><li>define ('ROOT_DIR', dirname(dirname(dirname(__FILE__)))); </li></ul><ul><li>defin...
Know the market – Zend Framework <ul><li>// use the viewrenderer to keep the code DRY instantiate and add the helper in on...
Know the market – Zend Framework <ul><li>Zend Framework is different. </li></ul><ul><ul><li>It is not a solid application ...
A broader view on your framework <ul><li>MVC Push or Pull </li></ul><ul><ul><li>MVC Push or Passive View </li></ul></ul><u...
A broader view on your framework <ul><li>MVC Push or Pull </li></ul><ul><ul><li>MVC Pull or so-called HMVC (see next): bre...
A broader view on your framework
 
A broader view on your framework <ul><li>MVC Push or Pull:  HMVC implementation </li></ul><ul><ul><li>Master Controller </...
A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Group Controller </li...
A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Element Controller </...
A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Element Controller te...
A broader view on your framework <ul><li>IDE support </li></ul><ul><ul><li>Code completion rocks </li></ul></ul><ul><ul><l...
A broader view on your framework <ul><li>Core feature set </li></ul><ul><ul><li>MVC framework </li></ul></ul><ul><ul><ul><...
A broader view on your framework <ul><li>Core feature set </li></ul><ul><ul><li>Validation framework </li></ul></ul><ul><u...
A broader view on your framework <ul><li>Much more things that need to take into account </li></ul><ul><ul><li>Behavior la...
Lessons to learn <ul><li>Take your hand dirty please. </li></ul><ul><li>Singleton is bad thing when dependency injection a...
Lessons to learn <ul><li>Factory and interface make good things </li></ul><ul><ul><li>Factory and Adapter are good for ser...
Lessons to learn <ul><li>Fluent interface/object chaining sometimes is a bad thing </li></ul><ul><ul><li>Law of Demeter </...
Lessons to learn <ul><li>Don’t think DAO or ActiveRecord, think Domain Respository </li></ul>
Lessons to learn <ul><li>An interface between Model and Controller must be defined </li></ul><ul><ul><li>Model class retur...
Lessons to learn <ul><li>Dependency Injection </li></ul><ul><ul><li>Does all injection through the constructor </li></ul><...
Design by Interface <ul><li>Rule: Don’t call me, I will call you </li></ul><ul><li>Template Method </li></ul><ul><li>Conve...
Thanks you <ul><li>Any question? </li></ul>
Upcoming SlideShare
Loading in...5
×

Hanoi php day 2008 - 01.pham cong dinh - how.to.build.your.own.framework

2,959

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,959
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
43
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide
  • You need to think different. You can not see it in a 1999 manner. Java purist mindsets are obsolete
  • Transcript of "Hanoi php day 2008 - 01.pham cong dinh - how.to.build.your.own.framework"

    1. 1. How to learn to build your own PHP framework Bridging the gap between PHP, OOP and Software Architecture Pham Cong Dinh (a.k.a pcdinh) Software Developer Hanoi PHP Day - December 2008 Hanoi - Vietnam
    2. 2. Introduction <ul><li>A foundation member of JavaVietnam since 2003 ( http://www.javavietnam.org ) </li></ul><ul><li>A foundation member of PHPVietnam Discussion Group since 2004 ( http://groups.google.com/group/phpvietnam ) </li></ul><ul><li>Lead web developer with World’Vest Base Inc. </li></ul><ul><li>Java is my first love since 1999 </li></ul><ul><li>PHP is my real lover since 2003. I love the way PHP community works </li></ul><ul><li>Sometimes I works on Python, Ruby, Erlang </li></ul><ul><li>I am a strong believer in dynamic programming languages, JavaScript, web standards, convergence of web as a platform and Outsourcing 2.0 </li></ul><ul><li>I spent 2 years to play with my framework named Pone (PHP One) </li></ul>
    3. 3. Objectives <ul><li>Where is PHP now? It is changing. </li></ul><ul><ul><li>Enterprise oriented: which is driven by Yahoo, Facebook, Zend, Sun/MySQL, Oracle, OmniTI … PHP is too big. It can not just be ignored </li></ul></ul><ul><ul><li>Object Oriented Programming adoption </li></ul></ul><ul><ul><li>Increased complexity of web applications </li></ul></ul><ul><ul><li>Web vs. Adobe Air, MS Silverlight, JavaFX, Google Native Client </li></ul></ul><ul><ul><li>Trends Will Move Applications to the Web: Consumer Innovation Setting the Pace, Rise of the Power Collaborator, New Economics of Scale for IT, Barriers to Adoption Are Falling </li></ul></ul><ul><ul><li>Scale-out wins </li></ul></ul><ul><li>Understanding what framework designers think </li></ul><ul><li>Building up shared mindsets </li></ul><ul><li>Providing food for thought </li></ul>
    4. 4. Agenda – 40 slides <ul><li>Making judgments </li></ul><ul><li>Top notch frameworks and their shortcomings </li></ul><ul><li>A broader view on your framework </li></ul><ul><li>Lessons to learn </li></ul>
    5. 5. Making judgments <ul><li>Common wisdom: Reinventing the wheel </li></ul><ul><li>Good </li></ul><ul><ul><li>You know it inside and out </li></ul></ul><ul><ul><li>You control its pace </li></ul></ul><ul><ul><li>It fits your needs. Sometimes, your need is unique </li></ul></ul><ul><ul><li>It teaches you how the world around you works </li></ul></ul><ul><ul><li>License: This is why GPL is sometime a bad thing </li></ul></ul><ul><li>Bad </li></ul><ul><ul><li>You may not as good as other ones </li></ul></ul><ul><ul><li>No community </li></ul></ul><ul><ul><li>No outside contributors </li></ul></ul><ul><ul><li>Reinventing the square wheel </li></ul></ul>
    6. 6. Making judgments <ul><li>To develop a framework is just like to set up a business </li></ul><ul><li>Think of your limitation: time, resources, knowledge to build/test/document/maintain your own mental baby </li></ul><ul><li>Know your team: how to train them </li></ul><ul><li>Know the market : known frameworks in the market. Sometimes your needs are satisfied to some extent in several little-known frameworks </li></ul><ul><li>Starts with pencil and paper: its components and how they interact </li></ul><ul><li>Starts with API: learn how to design an API first </li></ul><ul><li>You never do it right from day one </li></ul>
    7. 7. Know the market <ul><li>CakePHP shortcomings </li></ul><ul><li>Zend Framework shortcomings </li></ul><ul><li>Third party frameworks shortcomings </li></ul>
    8. 8. Know the market - CakePHP <ul><li>Misleading terms: plugin, model… </li></ul><ul><ul><li>Plugin: CakePHP allows you to set up a combination of controllers, models, and views and release them as a packaged application </li></ul></ul><ul><li>Too database centric: CakePHP naming convention is driven by table names, not dependency injection mechanism. </li></ul><ul><li>Admin routing sucks: why do we need one-and-only backend for the whole application/plugin/etc…? </li></ul><ul><li>Flat application structure: plugin/controller/action and no more. </li></ul><ul><li>Global space constants </li></ul>
    9. 9. Know the market - CakePHP <ul><li>No elegant way to change media file (css, javascript, meta content) on each layout page, controlled by a Controller. </li></ul><ul><li><head>    <?php echo $html->charset(); ?>    <title>         <?php echo $title_for_layout; ?>    </title>    <?php      echo $html->css('cake.generic');      echo $javascript->link('prototype-1.6.0.2');     echo $scripts_for_layout;      echo $html->meta('icon','/myapp/img/favicon.ico', array ('type' =>'icon'));    ?> </head> </li></ul>
    10. 10. Know the market - CakePHP <ul><li>loadModel(), loadController() are not about dependency injection </li></ul><ul><li>E.x: You want to provide access to a model from a Component Say you have a model called FooBar in a file called foo_bar.php </li></ul><ul><li>loadModel ('FooBar');   </li></ul><ul><li>$this ->FooBar = & new  FooBar(); </li></ul><ul><li>loadModel() maybe deprecated in favor of </li></ul><ul><li>App::import ('Model', 'ModelName'); </li></ul>
    11. 11. Know the market - CakePHP <ul><li>beforeFilter(), afterFilter() are coupled with a certain controller (controller is a heavy object. It should avoid being hit too soon) </li></ul><ul><li><?php   class   AppController   extends   Controller  {      var   $beforeFilter  =  array ( 'checkAccess' );      var   $components  =  array ( 'Acl' );      function   checkAccess() {     } } ?> </li></ul>
    12. 12. Know the market - CakePHP <ul><li>Reuse of view via elements with requestAction() is bad and expensive </li></ul><ul><ul><li>The dispatcher is called for each call to a controller (routing, figures out what (Plugin)/Controller/Action is request, loops through all $paths->controllerPaths files, to figure out what Controller to load) </li></ul></ul><ul><ul><li>The controller is set up again </li></ul></ul><ul><li>Behavior: controllerActAsModel </li></ul><ul><li>Controller is an interface to another tier </li></ul><ul><li>Controller is not designed to provide data for internal components </li></ul><ul><li>Cache unfriendly </li></ul>
    13. 13. Know the market - CakePHP <ul><li>Caching hits its hard time because there is no way to get generated view content </li></ul><ul><ul><li><?php </li></ul></ul><ul><ul><li>$this->element('helpbox', array(&quot;cache&quot; => array('time'=> &quot;+7 days&quot;,'key'=>'unique value'))); </li></ul></ul><ul><ul><li>?> </li></ul></ul><ul><li>What about URL-based caching, session/cookie-based caching, geo-based caching, date-based caching </li></ul><ul><ul><li>(there are a lot of things to tell about CakePHP but it is all for today) </li></ul></ul>
    14. 14. Know the market – Zend Framework <ul><li>Zend Framework tries to be a better PEAR </li></ul><ul><ul><li>Powered by a solid foundation </li></ul></ul><ul><ul><li>A solid and controllable licensing (CLA) </li></ul></ul><ul><ul><li>More strictly controlled development environment </li></ul></ul><ul><ul><li>Enterprise-oriented class library </li></ul></ul><ul><ul><li>A well-defined roadmap and versioning </li></ul></ul><ul><li>Zend Framework is a glue framework or framework-oriented class library </li></ul>
    15. 15. Know the market – Zend Framework <ul><li>Zend Framework is extremely big and bloated </li></ul><ul><ul><li>Zend Framework 1.6.2: 1261 file, 267 folders </li></ul></ul><ul><ul><li>Zend_Mail: 33 files </li></ul></ul><ul><ul><li>Zend_Pdf: 89 files </li></ul></ul><ul><ul><li>Zend_Controller: 50 files </li></ul></ul><ul><ul><li>Zend_View: 57 files </li></ul></ul><ul><ul><li>Drupal includes folders: 33 files </li></ul></ul><ul><li>Zend Framework is designed most like Java frameworks </li></ul><ul><ul><li>Small class file </li></ul></ul><ul><ul><li>Lot of classes: object graph is hard (see next) </li></ul></ul><ul><ul><li>Atomic responsibility </li></ul></ul><ul><ul><li>Strongly embrace design patterns </li></ul></ul>
    16. 17. Know the market – Zend Framework <ul><li>Everything is an object, even a HTML button or checkbox. The same to Java (see Apache Wicket, Tapestry, JBoss Seam) </li></ul><ul><ul><li>class Zend_View_Helper_FormReset extends Zend_View_Helper_FormElement </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>public function formReset($name = '', $value = 'Reset', $attribs = null) </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>$info = $this->_getInfo($name, $value, $attribs); </li></ul></ul><ul><ul><li>extract ($info); // name, value, attribs, options, listsep, disable </li></ul></ul><ul><ul><li>// check if disabled </li></ul></ul><ul><ul><li>$disabled = ''; </li></ul></ul><ul><ul><li>if ($disable) { </li></ul></ul><ul><ul><li>$disabled = ' disabled=&quot;disabled&quot;'; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>// get closing tag </li></ul></ul><ul><ul><li>$endTag = '>'; </li></ul></ul><ul><ul><li>if ($this->view->doctype()->isXhtml()) { </li></ul></ul><ul><ul><li>$endTag = ' />'; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>// Render button </li></ul></ul><ul><ul><li>$xhtml = '<input type=&quot;reset&quot;' </li></ul></ul><ul><ul><li>. ' name=&quot;' . $this->view->escape($name) . '&quot;' </li></ul></ul><ul><ul><li>. ' id=&quot;' . $this->view->escape($id) . '&quot;' </li></ul></ul><ul><ul><li>. $disabled; </li></ul></ul><ul><ul><li>. . . . . . . . . </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
    17. 18. Know the market – Zend Framework <ul><li>What Zend Framework brings </li></ul><ul><ul><li>Lot of files are loaded per request which is a bad thing for a dynamic, interpreted language and stateless platform like PHP </li></ul></ul><ul><ul><li>Much more memory usage </li></ul></ul><ul><ul><li>Bad thing for PHP memory management model in which memory is allocated in small chunks </li></ul></ul><ul><ul><li>Zend Framework code: There are lot of require_once() call inside an if statement which is bad for opcode caching mechanism </li></ul></ul><ul><ul><li>Zend Framework leaves shared hosting in the cold. </li></ul></ul><ul><ul><ul><li>700 sites per server are quite normal </li></ul></ul></ul><ul><ul><ul><li>No control over file system optimization </li></ul></ul></ul><ul><ul><ul><li>No control over memory </li></ul></ul></ul><ul><ul><ul><li>No control over opcode caching </li></ul></ul></ul>
    18. 19. Know the market – Zend Framework <ul><li>A glue framework requires you to know every concrete class and how to use them in a application life cycle </li></ul><ul><li>A lot of things to consider means bootstrapping is a mess </li></ul>
    19. 20. Know the market – Zend Framework <ul><li>define ('ROOT_DIR', dirname(dirname(dirname(__FILE__)))); </li></ul><ul><li>define ('APP_DIR',dirname(dirname(__FILE__))); </li></ul><ul><li>set_include_path ('.' . PATH_SEPARATOR . APP_DIR . '/lib/' . PATH_SEPARATOR . APP_DIR . '/application/default/models/' . PATH_SEPARATOR . ROOT_DIR . '/shared/lib/' . PATH_SEPARATOR . get_include_path()); </li></ul><ul><li>//This requires that your Zend library lies in ROOT_DIR/shared/lib/ </li></ul><ul><li>//make classes autoload without doing require </li></ul><ul><li>require_once ('Zend/Loader.php'); </li></ul><ul><li>Zend_Loader::registerAutoload(); </li></ul><ul><li>if ( defined ('ENV') !== TRUE) { </li></ul><ul><li>define ('ENV','production'); //change staging to production to go to production settings </li></ul><ul><li>} </li></ul><ul><li>$config = new Zend_Config_Xml(APP_DIR . '/config/config.xml', ENV); </li></ul><ul><li>Zend_Registry::set('config',$config); </li></ul><ul><li>//init session </li></ul><ul><li>$session = new Zend_Session_Namespace($config->session_name); </li></ul><ul><li>Zend_Registry::set('session',$session); </li></ul><ul><li>Zend_Db_Table::setDefaultAdapter(Zend_Db::factory(Zend_Registry::get('config')->database)); </li></ul><ul><li>/** </li></ul><ul><li>* Init the Smarty view wrapper and set smarty suffix to the view scripts. </li></ul><ul><li>*/ </li></ul><ul><li>$view = new EZ_View_Smarty($config->smarty->toArray()); </li></ul>
    20. 21. Know the market – Zend Framework <ul><li>// use the viewrenderer to keep the code DRY instantiate and add the helper in one go </li></ul><ul><li>$viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('ViewRenderer'); </li></ul><ul><li>$viewRenderer->setView($view); </li></ul><ul><li>$viewRenderer->setViewSuffix($config->smarty->suffix); </li></ul><ul><li>/** </li></ul><ul><li>* Set inflector for Zend_Layout </li></ul><ul><li>*/ </li></ul><ul><li>$inflector = new Zend_Filter_Inflector(':script.:suffix'); </li></ul><ul><li>$inflector->addRules(array(':script' => array ('Word_CamelCaseToDash', 'StringToLower'), 'suffix' => $config->layout->suffix)); </li></ul><ul><li>// Initialise Zend_Layout's MVC helpers </li></ul><ul><li>Zend_Layout::startMvc( array ('layoutPath' => ROOT_DIR.$config->layout->layoutPath, </li></ul><ul><li>'view' => $view, </li></ul><ul><li>'contentKey' => $config->layout->contentKey, </li></ul><ul><li>'inflector' => $inflector)); </li></ul><ul><li>$front = Zend_Controller_Front::getInstance(); </li></ul><ul><li>$front->setControllerDirectory(array( </li></ul><ul><li>'default' => '../application/default/controllers', </li></ul><ul><li>'blog' => '../application/blog/controllers', </li></ul><ul><li>)); </li></ul><ul><li>$front->throwExceptions(true); </li></ul><ul><li>// enable logging to default.log </li></ul><ul><li>$writer = new Zend_Log_Writer_Stream(APP_DIR.'/data/log/default.log'); </li></ul><ul><li>$logger = new Zend_Log($writer); </li></ul><ul><li>// give easy access to the logger </li></ul><ul><li>Zend_Registry::set('logger', $logger); </li></ul><ul><li>try { </li></ul><ul><li>$front->dispatch(); </li></ul><ul><li>} catch (Exception $e) { </li></ul><ul><li>echo nl2br($e->__toString()); </li></ul><ul><li>} </li></ul>
    21. 22. Know the market – Zend Framework <ul><li>Zend Framework is different. </li></ul><ul><ul><li>It is not a solid application framework like CakePHP, it is designed to be a platform on which other frameworks are built </li></ul></ul><ul><li>Technical details should be mentioned in another talk (enough for today) </li></ul>
    22. 23. A broader view on your framework <ul><li>MVC Push or Pull </li></ul><ul><ul><li>MVC Push or Passive View </li></ul></ul><ul><li><?php // Load the Savant3 class file and create an instance. require_once 'Savant3.php'; $tpl = new Savant3(); // Create a title. $name = &quot;Some Of My Favorite Books&quot;; // Generate an array of book authors and titles. $booklist = array(     array(         'author' => 'Hernando de Soto',         'title' => 'The Mystery of Capitalism'     ),     array(         'author' => 'Neal Stephenson',         'title' => 'Cryptonomicon'     ),     array(         'author' => 'Milton Friedman',         'title' => 'Free to Choose'     ) ); // Assign values to the Savant instance. $tpl->title = $name; $tpl->books = $booklist; // Display a template using the assigned values. $tpl->display('books.tpl.php'); ?> </li></ul>
    23. 24. A broader view on your framework <ul><li>MVC Push or Pull </li></ul><ul><ul><li>MVC Pull or so-called HMVC (see next): break a big controller into small ones </li></ul></ul>
    24. 25. A broader view on your framework
    25. 27. A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Master Controller </li></ul></ul><ul><ul><li>/** </li></ul></ul><ul><ul><li>* Show the home page </li></ul></ul><ul><ul><li>* </li></ul></ul><ul><ul><li>* @link http://www.wvbresearch.com/home/index/index </li></ul></ul><ul><ul><li>* @name index </li></ul></ul><ul><ul><li>* @access public </li></ul></ul><ul><ul><li>*/ </li></ul></ul><ul><ul><li>public function indexAction() </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>// Attach placeholder: the name of ElementGroup </li></ul></ul><ul><ul><li>$this->_layout->registerBody('homeIndex'); </li></ul></ul><ul><ul><li>// Set content for the response </li></ul></ul><ul><ul><li>$this->_response->setContent($this->_layout->render('index3col')); </li></ul></ul><ul><ul><li>} </li></ul></ul>
    26. 28. A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Group Controller </li></ul></ul><ul><ul><li>class Group_HomeIndex extends Pone_View_ElementGroup </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>/** </li></ul></ul><ul><ul><li> * Elements in in this group </li></ul></ul><ul><ul><li> * </li></ul></ul><ul><ul><li> * @var array </li></ul></ul><ul><ul><li> */ </li></ul></ul><ul><ul><li>protected $_elementsInGroup = array( </li></ul></ul><ul><ul><li>'homeTopNegativeEpsSurprises', 'homeTopPositiveEpsSurprises', </li></ul></ul><ul><ul><li>'homeIntroduction', 'brokerRatingsUpgrades', 'homeAnalystEstimatesSearchBox', </li></ul></ul><ul><ul><li>'homeResearchReportSearchBox', 'latestResearchReports' </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>protected $_templateFile = 'homeIndex'; </li></ul></ul><ul><ul><li>public function setup() </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
    27. 29. A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Element Controller </li></ul></ul><ul><ul><li>class Element_LatestResearchReports extends Pone_View_Element </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>protected $_templateFile = 'latestResearchReportsOnHome'; </li></ul></ul><ul><ul><li>/** </li></ul></ul><ul><ul><li>* List of recent research reports </li></ul></ul><ul><ul><li>* </li></ul></ul><ul><ul><li>* @var Pone_DataSet </li></ul></ul><ul><ul><li>*/ </li></ul></ul><ul><ul><li>public $researchReports; </li></ul></ul><ul><ul><li>public function setup() </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>$module = Pone::getContext()->getFront()->getRequest()->getModuleName(); </li></ul></ul><ul><ul><li>$numberOfItems = 7; </li></ul></ul><ul><ul><li>if ('home' !== $module) </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>$this->_templateFile = 'latestResearchReports'; </li></ul></ul><ul><ul><li>$numberOfItems = 10; </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>$dbConn = Pone_Action_Helper_Database::getInstance()->getConnection('oracleweb', true); </li></ul></ul><ul><ul><li>$researchReportDs = ResearchReportDatabaseService::getInstance($dbConn); </li></ul></ul><ul><ul><li>$this->researchReports = $researchReportDs->findRecentList($numberOfItems); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
    28. 30. A broader view on your framework <ul><li>MVC Push or Pull: HMVC implementation </li></ul><ul><ul><li>Element Controller template </li></ul></ul><ul><ul><li>< div class =&quot; featureBlockHeader &quot;> </li></ul></ul><ul><ul><li>< h2 >Latest reports</ h2 > </li></ul></ul><ul><ul><li></ div > </li></ul></ul><ul><ul><li>< div class=&quot; textBox &quot;> </li></ul></ul><ul><ul><li>< div class=&quot; textBoxContent &quot;> </li></ul></ul><ul><ul><li><?php if ( true === $this->researchReports->isReadable()): $iter = $this->researchReports->getIterator(); ?> </li></ul></ul><ul><ul><li>< ul class=&quot; imgList &quot;> </li></ul></ul><ul><ul><li><?php foreach ($iter as $report): ?> </li></ul></ul><ul><ul><li>< li ><a href=&quot;research/detail/view/rpid/<?php echo $report->get('report_id') ?>&quot;><?php echo $report->get('title'); ?></a></li> </li></ul></ul><ul><ul><li><?php endforeach; ?> </li></ul></ul><ul><ul><li></ul> </li></ul></ul><ul><ul><li><?php else: echo $this->researchReports->getMessage(); endif; ?> </li></ul></ul><ul><ul><li></ div > </li></ul></ul><ul><ul><li></ div > </li></ul></ul>
    29. 31. A broader view on your framework <ul><li>IDE support </li></ul><ul><ul><li>Code completion rocks </li></ul></ul><ul><ul><li>MVC Push is bad for view data documentation </li></ul></ul><ul><ul><li>Zend_Registry is bad for code completion </li></ul></ul><ul><ul><ul><li>Zend_Registry :: set('logger', $logger); </li></ul></ul></ul><ul><ul><li>Think of interface because implementing a way to load dynamic class from a variable or an array element. </li></ul></ul><ul><ul><li>Learn how to write DocBlock </li></ul></ul>
    30. 32. A broader view on your framework <ul><li>Core feature set </li></ul><ul><ul><li>MVC framework </li></ul></ul><ul><ul><ul><li>Model layer: DBO, File handling/transformation, business rules, workflows, search, messaging, memory, remote resource access … </li></ul></ul></ul><ul><ul><li>Validation framework instead of form handling </li></ul></ul><ul><ul><li>Unified directory structure: model classes, controllers, views (page fragments, layouts), plugins, filters, custom exceptions, helpers </li></ul></ul><ul><ul><li>Session </li></ul></ul><ul><ul><li>Authentication and ACL: Abstract and extensible </li></ul></ul><ul><ul><ul><li>HTTP Digest </li></ul></ul></ul><ul><ul><ul><li>Database backed </li></ul></ul></ul><ul><ul><ul><li>SAML/SSO </li></ul></ul></ul><ul><ul><ul><li>Serializable Unified Session User Object </li></ul></ul></ul>
    31. 33. A broader view on your framework <ul><li>Core feature set </li></ul><ul><ul><li>Validation framework </li></ul></ul><ul><ul><li>class Form_Signup extends Pone_Form_Input </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>. . . . . . </li></ul></ul><ul><ul><li>public function onPost() </li></ul></ul><ul><ul><li>{ </li></ul></ul><ul><ul><li>// Email </li></ul></ul><ul><ul><li>$emailRules = array( </li></ul></ul><ul><ul><li>Pone_Form_Rule::EMAIL => array('feedback' => _t('common.error.email.notvalid')) </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>$this->setValidationRule('email', $emailRules); </li></ul></ul><ul><ul><li>// Email 2 </li></ul></ul><ul><ul><li>$email2Rules = array( </li></ul></ul><ul><ul><li>Pone_Form_Rule::STRING_EQUAL => array('feedback' => _t('common.error.reemail.not_match'), </li></ul></ul><ul><ul><li>'reference' => 'email') </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>$this->setValidationRule('email2', $email2Rules); </li></ul></ul><ul><ul><li>// password </li></ul></ul><ul><ul><li>$passwordRules = array( </li></ul></ul><ul><ul><li>Pone_Form_Rule::NOT_EMPTY => array('feedback' => _t('common.error.password.empty')) </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>$this->setValidationRule('password', $passwordRules); </li></ul></ul><ul><ul><li>// password 2 </li></ul></ul><ul><ul><li>$password2Rules = array( </li></ul></ul><ul><ul><li>Pone_Form_Rule::STRING_EQUAL => array('feedback' => _t('common.error.repassword.not_match'), </li></ul></ul><ul><ul><li>'reference' => 'password') </li></ul></ul><ul><ul><li>); </li></ul></ul><ul><ul><li>$this->setValidationRule('password2', $password2Rules); </li></ul></ul><ul><ul><li>} </li></ul></ul><ul><ul><li>} </li></ul></ul>
    32. 34. A broader view on your framework <ul><li>Much more things that need to take into account </li></ul><ul><ul><li>Behavior layer </li></ul></ul><ul><ul><li>Caching </li></ul></ul><ul><ul><ul><li>Distributed caching </li></ul></ul></ul><ul><ul><ul><li>Local caching </li></ul></ul></ul><ul><ul><li>Dependency Injection framework </li></ul></ul><ul><ul><li>Internationalization </li></ul></ul><ul><ul><li>(enough for today) </li></ul></ul>
    33. 35. Lessons to learn <ul><li>Take your hand dirty please. </li></ul><ul><li>Singleton is bad thing when dependency injection and unit testing are taken into consideration </li></ul><ul><ul><li>can't replace it with an interface </li></ul></ul><ul><ul><li>Factory allows for both discovery and instance management of the service providers </li></ul></ul><ul><ul><li>Final classes should keep singleton objects </li></ul></ul><ul><ul><li>$dbConn = Pone_Action_Helper_Database :: getInstance ()->getConnection('oracleweb', true); </li></ul></ul><ul><ul><li>$researchReportDs = ResearchReportDatabaseService :: getInstance ($dbConn); </li></ul></ul><ul><ul><li>$this->researchReports = $researchReportDs->findRecentList($numberOfItems); </li></ul></ul>
    34. 36. Lessons to learn <ul><li>Factory and interface make good things </li></ul><ul><ul><li>Factory and Adapter are good for service providers </li></ul></ul><ul><li>$conn = Pone_Database_ConnectionFactory::getConnection($config); </li></ul><ul><li>$stmt = $conn->createStatement(); </li></ul><ul><li>$stmt ->addBatch(&quot;INSERT INTO test2 VALUES (1007, 'pcdinh1007', 1)&quot;); </li></ul><ul><li>$stmt ->addBatch(&quot;INSERT INTO test2 VALUES (1009, 'pcdinh1009', 1)&quot;); </li></ul><ul><li>$stmt ->addBatch(&quot;INSERT INTO test2 VALUES (1010, 'pcdinh1010', 1)&quot;); </li></ul><ul><li>$conn ->beginTransaction(); </li></ul><ul><li>$updateCounts = $stmt->executeBatch(); </li></ul>
    35. 37. Lessons to learn <ul><li>Fluent interface/object chaining sometimes is a bad thing </li></ul><ul><ul><li>Law of Demeter </li></ul></ul><ul><li>$module = Pone::getContext()->getFront()->getRequest()->getModuleName(); </li></ul>
    36. 38. Lessons to learn <ul><li>Don’t think DAO or ActiveRecord, think Domain Respository </li></ul>
    37. 39. Lessons to learn <ul><li>An interface between Model and Controller must be defined </li></ul><ul><ul><li>Model class returns an array: bad thing. How to catch errors and deal with them in the view template </li></ul></ul>
    38. 40. Lessons to learn <ul><li>Dependency Injection </li></ul><ul><ul><li>Does all injection through the constructor </li></ul></ul><ul><ul><li>$libBasePath = $basePath.'/libs'; </li></ul></ul><ul><ul><li>$appBasePath = $basePath.'/apps'; </li></ul></ul><ul><ul><li>Pone::executeContext( new BenchmarkContext() , $basePath, $appBasePath, $libBasePath); </li></ul></ul><ul><ul><li>OR </li></ul></ul><ul><ul><li>$front->setRequest(new Pone_Request( new Pone_Request_SimpleUrlParser() )); </li></ul></ul><ul><ul><li>Use Template Method design pattern </li></ul></ul><ul><ul><ul><li>Seam </li></ul></ul></ul><ul><ul><ul><li>if (session_id() === '' && PHP_SAPI != 'cli') </li></ul></ul></ul><ul><ul><ul><li>{ </li></ul></ul></ul><ul><ul><ul><li>Pone::getContext()->loadSessionUserClass(); </li></ul></ul></ul><ul><ul><ul><li>$started = session_start(); // PHP 5.3: returns false or true </li></ul></ul></ul><ul><ul><ul><li>$this->_started = true; </li></ul></ul></ul><ul><ul><ul><li>} </li></ul></ul></ul><ul><ul><li>Use XML/YAML like in Spring, Symfony which is somewhat heavy in an interpreted language like PHP </li></ul></ul>
    39. 41. Design by Interface <ul><li>Rule: Don’t call me, I will call you </li></ul><ul><li>Template Method </li></ul><ul><li>Convention over configuration </li></ul><ul><li>That’s end for today </li></ul>
    40. 42. Thanks you <ul><li>Any question? </li></ul>
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×