SlideShare a Scribd company logo
1 of 45
Download to read offline
Using and Reusing

                               PLUGINS
                      Across                   applications




CakeFest 2010 - Chicago                                       Pierre MARTIN
ME
     June 2008 - CakePHP 1.2 beta

                CakePHP-fr




@pierremartin                http://pierre-martin.fr
YOU



                        ?
Used a plugin

Wrote a plugin

Reuse regularly
WHY
Spaghetti code

                   Libraries
          OOP, Templates
  MVC and Frameworks
       Fat Models    Skinny Controllers


+ Reusable classes (Behaviors, Components, Helpers)
REUSING CODE

             Plugins

                 Or

               CPSR


Copy and Paste / Search and Replace :)
HOW
/APP/PLUGINS
my_plugin/
  my_plugin_app_model.php            locale/
  my_plugin_app_controller.php           eng/
  models/                                    LC_MESSAGES/
     behaviors/                                 my_plugin.po (__d())
     my_plugin_foo.php               webroot/
     my_plugin_bar.php                   css/
  controllers/                               style.css
     components/                             other.css
     my_plugin_foos_controller.php       img/
     my_plugin_bars_controller.php           logo.png
  views/                                 js/
     helpers/                                foobar.js
     layouts/                        tests/
     elements/                       libs/
     my_plugin_foos/                 vendors/
        index.ctp
     my_plugin_bars/
        add.ctp
MODELS
/app/plugins/users/models/user.php

ClassRegistry::init(‘Users.User’);

App::import(‘Model’, ‘Users.User’);

public $belongsTo = array(‘Users.User’);
public $belongsTo = array(
  ‘User’ => array(
      ‘className’ => ‘Users.User’));

public $belongsTo = array(
  ‘User’ => array(
      ‘className’ => ‘Users.UsersUser’));
PLUGIN.THING
It works for everything!

// Behaviors
public $actsAs = array(‘Comments.Commentable’);

// Components
public $components = array(‘Twitter.TwitterAuth’);

// Helpers
public $helpers = array(‘Tags.TagCloud’);

// Libraries, Vendors, Custom routes...
App::import(‘Lib’, ‘Chuck.Norris’);
ACTIONS / ELEMENTS
/app/plugins/users/controllers/users_controller.php
/app/plugins/users/views/elements/login.ctp


$this->redirect(‘plugin’ => ‘users’, ‘controller’ => ‘users’, ‘action’ => ‘register’);
$this->redirect(‘plugin’ => null, ‘controller’ => ‘pages’, ‘action’ => ‘display’, ‘home’);

$this->Html->link(‘plugin’ => ‘users’, ‘controller’ => ‘users’, ‘action’ => ‘index’);
// Will generate http://domain.com/users

$this->element(‘login’, array(‘plugin’ => ‘users’, ‘foo’ => ‘bar’));
ASSETS
/app/plugins/jquery/webroot/js/jquery.js
/app/plugins/jquery/webroot/css/jquery.ui.css
/app/plugins/jquery/webroot/img/subdir/logo.png


$this->Html->script(‘/jquery/js/jquery.js’);

$this->Html->css(‘/jquery/css/jquery.ui.css’);

$this->Html->image(‘/jquery/img/subdir/logo.png’);
Source: @dogmatic69
EXTENDING
 PLUGINS
WHY?

  Appearance customization

       App specific logic

Changing features, redirections...

        Adding features
“USERS” PLUGIN

• User model
 • id, username, password
• Users Controller
 • login, logout, register, reset_password
• Views
VIEWS
/app/plugins/users/views/users/register.ctp
/app/views/plugins/users/users/register.ctp
<h1><?php __(‘Create a new account on Awesomeness.org’); ?>
<?php
   echo $this->Form->create(‘User’);
   echo $this->Form->input(‘username’);
   echo $this->Form->input(‘password’);
   echo $this->Form->input(‘password_confirm’);
   // App specific feature
   echo $this->Form->input(‘Profile.newsletter’, array(
       ‘label’ => __(‘Suscribe to our newsletter’, true),
       ‘type’ => ‘checkbox’));
   echo $this->Form->end(__(‘I want to be awesome!’, true));
?>
MODELS
<?php
App::import(‘Model’, ‘Users.User’);
class MyUser extends User {
    // [...]
    public $hasOne = array(‘Profile’);
    // [...]
    public function __construct($id = false, $table = null, $ds = null) {
         parent::__construct($id, $table, $ds);
         $this->validate[‘username’][‘length’] = array(
             ‘rule’ => array(‘minLength’, 5));
    }
    // [...]
    public function register($data) {
         $success = parent::register($data);
         if ($success) {
             // Your business logic here
         }
         return $success;
    }
    // [...]
    public function foobar() { }
}
?>
CONTROLLERS
<?php
App::import(‘Controller’, ‘Users.Users’);
class MyUsersController extends UsersController {
    // [...]
    public function beforeFilter() {
         $this->User = ClassRegistry::init('MyUser');
         parent::beforeFilter();
         $this->Auth->deny('index');
    }
    // [...]
    public function register() {
         if (!empty($this->data)) {
              if ($this->User->register($this->data)) {
                  // Your app specific logic here
                  $this->redirect(‘controller’ => ‘pages’, ‘action’ => ‘display’, ‘welcome’);
              }
         }
         parent::register();
    }
    // [...]
    public function foobar() { }
}
?>
TO
                                                                         DO
                                                                            I               mp
                         CONTROLLERS                                                                 rov
                                                                                                        em
                                                                                                             e
Router::connect(
  '/users/:action/*',
  array('plugin' => ‘users’, 'controller' => 'users'));
Router::connect(
  '/users/:action/*',
  array('plugin' => null, 'controller' => 'my_users'));



public function render($action = null, $layout = null, $file = null) {
    if (is_null($action)) {
            $action = $this->action;
    }
    if ($action !== false) {
	

     if (!file_exists(VIEWS . 'my_users' . DS . $action . '.ctp')) {
	

     	

      $file = App::pluginPath('users') . 'views' . DS . 'users' . DS . $action . '.ctp';
	

     }
    }
    return parent::render($action, $layout, $file);
}
... AND IT WORKS WITH
          EVERYTHING
    Helpers, Libraries, Components, Behaviors...



App::import(‘Behavior’, ‘Comments.Commentable’);
class MyCommentable extends Commentable {

}
TIPS AND
 TRICKS
 Serious stuff coming!
DON’T
TRUST ME!
 Unless you’ve tried it yourself
REUSE EXISTING PLUGINS
CakePHP’s main feature is its community
CakePackages.com:
 •548 CakePHP related projects
 •284 developers
KISS




Refactor          Extend
USE OBJECTS ATTRIBUTES
// Models
$this->alias
$this->name
$this->displayField
$this->primaryKey

$this->data[‘User’][‘id’]; // Before
$this->data[$this->alias][$this->primaryKey]; // After


// Controllers
$this->plugin
$this->modelClass // MyModel
$this->modelKey // my_model
$this->name



              Add attributes to your classes!
COMPONENTS ARE THE KEY!


    Add some magic in your plugins
HELPER AUTOLOADING

class CommentManager extends Object {
   public $autoHelper = true;

    public $helperName = ‘Comments.CommentWidget’;

    public function beforeRender(Controller $Controller) {
      if ($this->autoHelper) {
          $Controller->helpers[] = $helperName;
      }
    }
}
BEHAVIOR AUTOLOADING
class CommentManager extends Object {
   public $autoBehavior = true;

    public $behaviorName = ‘Comments.Commentable’;

    public function startup(Controller $Controller) {
      $Model = $Controller->{$Controller->modelClass};
      if ($autoBehavior && !$Model->Behaviors->attached($this->behaviorName)) {
      	

    $Model->Behaviors->attach($this->behaviorName);
      }
    }
}
AUTODETECTED ACTIONS

class CommentManager extends Object {
   public $autoActions = true;

    public function startup(Controller $Controller) {
      if ($autoActions) {
          if (!empty($Controller->data[‘Comment’])) {
              // [...] Automatically save the comment
              $Controller->redirect($Controller->referer());
          }
      }
    }
}
AUTO DATA FETCHING

class FoobarManager extends Object {

    public function beforeRender(Controller $Controller) {
      $data = [...]; // Your logic here to get the correct data for the view
      $Controller->set(‘data_for_foobar_helper’, $data);
    }

}
HELPERS THAT HELP

 •   Reduce PHP code in views

 •      Unique entry point

 •      Deal with elements

 •   Performance optimization
... BEHIND THE SCENE

class FoobarHelper extends AppHelper {

    public function beforeRender() {
    	

 if (ClassRegistry::isKeySet('view')) {
    	

 	

   $View = ClassRegistry::getObject('view');
    	

 	

   $this->_data = $View->getVar('data_for_foobar_helper');
	

     }
    }

}
public function display($element = 'carts/view', $options) {
	

     if (!ClassRegistry::isKeySet('view')) { return; }

	

   if (empty($cartData)) {
	

   	

   if (is_a($this->Session, 'SessionHelper') && $this->Session->check('Cart')) {
	

   	

   	

    $cartData = $this->Session->read('Cart');
	

   	

   } else {
	

   	

   	

    $cartData = $this->requestAction($this->cartRequestUrl);
	

   	

   }
	

   }

	

   if (empty($cartData)) {
	

   	

   trigger_error(__d('cart', 'No cart found.', true), E_USER_NOTICE);
	

   } else {
	

   	

   // [...] Format the data and add default options (caching...)
	

   	

   $options['cartData'] = $cartData;
	

   	

   return ClassRegistry::getObject('view')->element($element, $options);
	

   }
}
USE THE CONFIGURE CLASS
• With   default values

• Configure::load()


      public function __construct($id = false, $table = null, $ds = null) {
      	

     $userClass = Configure::read('App.UserClass');
      	

     if (empty($userClass)) {
      	

     	

    $userClass = 'User';
      	

     }
      	

     $this->belongsTo['User'] = array(
      	

     	

    'className' => $userClass,
      	

     	

    'foreignKey' => 'user_id');
            // [...]
      }
CALLBACKS / HOOKS
class StuffableBehavior extends ModelBehavior {

    public function doStuff(Model $Model, $id) {
      if ($Model->isStuffable($id)) {
          // [...]
          if (method_exists($Model, ‘afterStuff’)) {
              $Model->afterStuff();
          }
      }
    }

    // Fallback, default logic
    public function isStuffable(Model $Model, $id) {
        return true;
    }

}
HIGHLIGHT ERRORS
               Trigger errors for the developer

                Throw Exceptions for the User

$mandatory = Configure::read('Foo.bar');
if (empty($mandatory)) {
    trigger_error(‘You must configure your Foobar’, E_USER_ERROR);
}


public function doStuff($id) {
  $Model->id = $id;
  if (!$Model->exists($id)) {
      throw new OutOfBoundsException(__(‘Invalid object’, true));
  }
}
MAKE MIGRATIONS EASY
• Version    your code, tag versions (KISS, Extend, Refactor)

• Document API      changes between versions

• Use   CakeDC’s awesome Migrations plugin!

 • Schema      updates

 • Initial   data

 • Configuration     assistance
... AND ALSO
• Write   tests

• Use   __d(‘myplugin’, ‘This is my text’);

• Document        your code

• Provide   interfaces to implement (Lib)

• Write   tests... really!
WHAT IS
MISSING?
NAMESPACES

 ClassRegistry downsides


MyPluginFoobarsController
PLUGINS DIRECTORY

        Reduce plugin duplication

“Diversity is good... with moderation”



           CakePackages.com
PLUGIN MANAGER

         Shell


   Generic installer

      Migrations
METADATA

       Version


    Dependencies


Implemented “Interface”
QUESTIONS?


@pierremartin   http://pierre-martin.fr

More Related Content

What's hot

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010Fabien Potencier
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Luka Zakrajšek
 
Comment pages 002
Comment pages 002Comment pages 002
Comment pages 002RiNi Ft
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonKris Wallsmith
 
Mulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitRebecca Murphey
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Binary Studio Academy 2016: Laravel Controllers
Binary Studio Academy 2016: Laravel ControllersBinary Studio Academy 2016: Laravel Controllers
Binary Studio Academy 2016: Laravel ControllersBinary Studio
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony AppsKris Wallsmith
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery ApplicationsRebecca Murphey
 
Drupal is Stupid (But I Love It Anyway)
Drupal is Stupid (But I Love It Anyway)Drupal is Stupid (But I Love It Anyway)
Drupal is Stupid (But I Love It Anyway)brockboland
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Fabien Potencier
 
Settings API - Oslo WordPress Meetup - November 22, 2011
Settings API - Oslo WordPress Meetup - November 22, 2011Settings API - Oslo WordPress Meetup - November 22, 2011
Settings API - Oslo WordPress Meetup - November 22, 2011WPOslo
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Ruby on Rails : RESTful 和 Ajax
Ruby on Rails : RESTful 和 AjaxRuby on Rails : RESTful 和 Ajax
Ruby on Rails : RESTful 和 AjaxWen-Tien Chang
 

What's hot (20)

The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010The state of Symfony2 - SymfonyDay 2010
The state of Symfony2 - SymfonyDay 2010
 
Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
 
Comment pages 002
Comment pages 002Comment pages 002
Comment pages 002
 
Matters of State
Matters of StateMatters of State
Matters of State
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
How kris-writes-symfony-apps-london
How kris-writes-symfony-apps-londonHow kris-writes-symfony-apps-london
How kris-writes-symfony-apps-london
 
Mulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development ToolkitMulberry: A Mobile App Development Toolkit
Mulberry: A Mobile App Development Toolkit
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
The Settings API
The Settings APIThe Settings API
The Settings API
 
Binary Studio Academy 2016: Laravel Controllers
Binary Studio Academy 2016: Laravel ControllersBinary Studio Academy 2016: Laravel Controllers
Binary Studio Academy 2016: Laravel Controllers
 
How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
Building Large jQuery Applications
Building Large jQuery ApplicationsBuilding Large jQuery Applications
Building Large jQuery Applications
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
Drupal is Stupid (But I Love It Anyway)
Drupal is Stupid (But I Love It Anyway)Drupal is Stupid (But I Love It Anyway)
Drupal is Stupid (But I Love It Anyway)
 
Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2Unit and Functional Testing with Symfony2
Unit and Functional Testing with Symfony2
 
Settings API - Oslo WordPress Meetup - November 22, 2011
Settings API - Oslo WordPress Meetup - November 22, 2011Settings API - Oslo WordPress Meetup - November 22, 2011
Settings API - Oslo WordPress Meetup - November 22, 2011
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Keeping It Simple
Keeping It SimpleKeeping It Simple
Keeping It Simple
 
Ruby on Rails : RESTful 和 Ajax
Ruby on Rails : RESTful 和 AjaxRuby on Rails : RESTful 和 Ajax
Ruby on Rails : RESTful 和 Ajax
 
Feeds drupal cafe
Feeds drupal cafeFeeds drupal cafe
Feeds drupal cafe
 

Similar to Using and reusing CakePHP plugins

Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For BeginnersJonathan Wage
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)arcware
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of PluginYasuo Harada
 
Catalyst patterns-yapc-eu-2016
Catalyst patterns-yapc-eu-2016Catalyst patterns-yapc-eu-2016
Catalyst patterns-yapc-eu-2016John Napiorkowski
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Building scalable products with WordPress - WordCamp London 2018
Building scalable products with WordPress - WordCamp London 2018Building scalable products with WordPress - WordCamp London 2018
Building scalable products with WordPress - WordCamp London 2018Elliot Taylor
 
CFUGbe talk about Angular JS
CFUGbe talk about Angular JSCFUGbe talk about Angular JS
CFUGbe talk about Angular JSAlwyn Wymeersch
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf Conference
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection apiMatthieu Aubry
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Fabio Biondi
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkDirk Haun
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium AppsNate Abele
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From IusethisMarcus Ramberg
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverSpike Brehm
 

Similar to Using and reusing CakePHP plugins (20)

Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
10 Things Every Plugin Developer Should Know (WordCamp Atlanta 2013)
 
Quality Use Of Plugin
Quality Use Of PluginQuality Use Of Plugin
Quality Use Of Plugin
 
Catalyst patterns-yapc-eu-2016
Catalyst patterns-yapc-eu-2016Catalyst patterns-yapc-eu-2016
Catalyst patterns-yapc-eu-2016
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Pluggin creation
Pluggin creationPluggin creation
Pluggin creation
 
Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2Angular Workshop_Sarajevo2
Angular Workshop_Sarajevo2
 
Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
 
Building scalable products with WordPress - WordCamp London 2018
Building scalable products with WordPress - WordCamp London 2018Building scalable products with WordPress - WordCamp London 2018
Building scalable products with WordPress - WordCamp London 2018
 
AngularJs-training
AngularJs-trainingAngularJs-training
AngularJs-training
 
CFUGbe talk about Angular JS
CFUGbe talk about Angular JSCFUGbe talk about Angular JS
CFUGbe talk about Angular JS
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
Easy rest service using PHP reflection api
Easy rest service using PHP reflection apiEasy rest service using PHP reflection api
Easy rest service using PHP reflection api
 
Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)Single Page Applications in Angular (italiano)
Single Page Applications in Angular (italiano)
 
Using Geeklog as a Web Application Framework
Using Geeklog as a Web Application FrameworkUsing Geeklog as a Web Application Framework
Using Geeklog as a Web Application Framework
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
Bag Of Tricks From Iusethis
Bag Of Tricks From IusethisBag Of Tricks From Iusethis
Bag Of Tricks From Iusethis
 
Introducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and serverIntroducing Rendr: Run your Backbone.js apps on the client and server
Introducing Rendr: Run your Backbone.js apps on the client and server
 

More from Pierre MARTIN

Introduction à CakePHP
Introduction à CakePHPIntroduction à CakePHP
Introduction à CakePHPPierre MARTIN
 
Building custom APIs
Building custom APIsBuilding custom APIs
Building custom APIsPierre MARTIN
 
Test and API-driven development of CakePHP Behaviors
Test and API-driven development of CakePHP BehaviorsTest and API-driven development of CakePHP Behaviors
Test and API-driven development of CakePHP BehaviorsPierre MARTIN
 
Recipes for successful CakePHP projects
Recipes for successful CakePHP projectsRecipes for successful CakePHP projects
Recipes for successful CakePHP projectsPierre MARTIN
 
The CakePHP Media Plugin
The CakePHP Media PluginThe CakePHP Media Plugin
The CakePHP Media PluginPierre MARTIN
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsPierre MARTIN
 

More from Pierre MARTIN (6)

Introduction à CakePHP
Introduction à CakePHPIntroduction à CakePHP
Introduction à CakePHP
 
Building custom APIs
Building custom APIsBuilding custom APIs
Building custom APIs
 
Test and API-driven development of CakePHP Behaviors
Test and API-driven development of CakePHP BehaviorsTest and API-driven development of CakePHP Behaviors
Test and API-driven development of CakePHP Behaviors
 
Recipes for successful CakePHP projects
Recipes for successful CakePHP projectsRecipes for successful CakePHP projects
Recipes for successful CakePHP projects
 
The CakePHP Media Plugin
The CakePHP Media PluginThe CakePHP Media Plugin
The CakePHP Media Plugin
 
Internationalizing CakePHP Applications
Internationalizing CakePHP ApplicationsInternationalizing CakePHP Applications
Internationalizing CakePHP Applications
 

Recently uploaded

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Angeliki Cooney
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesrafiqahmad00786416
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxRustici Software
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyKhushali Kathiriya
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityWSO2
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...Zilliz
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MIND CTI
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodJuan lago vázquez
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDropbox
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businesspanagenda
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelDeepika Singh
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Zilliz
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Jeffrey Haguewood
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
 

Recently uploaded (20)

Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
Biography Of Angeliki Cooney | Senior Vice President Life Sciences | Albany, ...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
ICT role in 21st century education and its challenges
ICT role in 21st century education and its challengesICT role in 21st century education and its challenges
ICT role in 21st century education and its challenges
 
Corporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptxCorporate and higher education May webinar.pptx
Corporate and higher education May webinar.pptx
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
Artificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : UncertaintyArtificial Intelligence Chap.5 : Uncertainty
Artificial Intelligence Chap.5 : Uncertainty
 
Platformless Horizons for Digital Adaptability
Platformless Horizons for Digital AdaptabilityPlatformless Horizons for Digital Adaptability
Platformless Horizons for Digital Adaptability
 
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ..."I see eyes in my soup": How Delivery Hero implemented the safety system for ...
"I see eyes in my soup": How Delivery Hero implemented the safety system for ...
 
MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024MINDCTI Revenue Release Quarter One 2024
MINDCTI Revenue Release Quarter One 2024
 
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin WoodPolkadot JAM Slides - Token2049 - By Dr. Gavin Wood
Polkadot JAM Slides - Token2049 - By Dr. Gavin Wood
 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
 
DBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor PresentationDBX First Quarter 2024 Investor Presentation
DBX First Quarter 2024 Investor Presentation
 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot ModelMcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
Mcleodganj Call Girls 🥰 8617370543 Service Offer VIP Hot Model
 
Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)Introduction to Multilingual Retrieval Augmented Generation (RAG)
Introduction to Multilingual Retrieval Augmented Generation (RAG)
 
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
Web Form Automation for Bonterra Impact Management (fka Social Solutions Apri...
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Using and reusing CakePHP plugins

  • 1. Using and Reusing PLUGINS Across applications CakeFest 2010 - Chicago Pierre MARTIN
  • 2. ME June 2008 - CakePHP 1.2 beta CakePHP-fr @pierremartin http://pierre-martin.fr
  • 3. YOU ? Used a plugin Wrote a plugin Reuse regularly
  • 4. WHY
  • 5. Spaghetti code Libraries OOP, Templates MVC and Frameworks Fat Models Skinny Controllers + Reusable classes (Behaviors, Components, Helpers)
  • 6. REUSING CODE Plugins Or CPSR Copy and Paste / Search and Replace :)
  • 7. HOW
  • 8. /APP/PLUGINS my_plugin/ my_plugin_app_model.php locale/ my_plugin_app_controller.php eng/ models/ LC_MESSAGES/ behaviors/ my_plugin.po (__d()) my_plugin_foo.php webroot/ my_plugin_bar.php css/ controllers/ style.css components/ other.css my_plugin_foos_controller.php img/ my_plugin_bars_controller.php logo.png views/ js/ helpers/ foobar.js layouts/ tests/ elements/ libs/ my_plugin_foos/ vendors/ index.ctp my_plugin_bars/ add.ctp
  • 9. MODELS /app/plugins/users/models/user.php ClassRegistry::init(‘Users.User’); App::import(‘Model’, ‘Users.User’); public $belongsTo = array(‘Users.User’); public $belongsTo = array( ‘User’ => array( ‘className’ => ‘Users.User’)); public $belongsTo = array( ‘User’ => array( ‘className’ => ‘Users.UsersUser’));
  • 10. PLUGIN.THING It works for everything! // Behaviors public $actsAs = array(‘Comments.Commentable’); // Components public $components = array(‘Twitter.TwitterAuth’); // Helpers public $helpers = array(‘Tags.TagCloud’); // Libraries, Vendors, Custom routes... App::import(‘Lib’, ‘Chuck.Norris’);
  • 11. ACTIONS / ELEMENTS /app/plugins/users/controllers/users_controller.php /app/plugins/users/views/elements/login.ctp $this->redirect(‘plugin’ => ‘users’, ‘controller’ => ‘users’, ‘action’ => ‘register’); $this->redirect(‘plugin’ => null, ‘controller’ => ‘pages’, ‘action’ => ‘display’, ‘home’); $this->Html->link(‘plugin’ => ‘users’, ‘controller’ => ‘users’, ‘action’ => ‘index’); // Will generate http://domain.com/users $this->element(‘login’, array(‘plugin’ => ‘users’, ‘foo’ => ‘bar’));
  • 15. WHY? Appearance customization App specific logic Changing features, redirections... Adding features
  • 16. “USERS” PLUGIN • User model • id, username, password • Users Controller • login, logout, register, reset_password • Views
  • 17. VIEWS /app/plugins/users/views/users/register.ctp /app/views/plugins/users/users/register.ctp <h1><?php __(‘Create a new account on Awesomeness.org’); ?> <?php echo $this->Form->create(‘User’); echo $this->Form->input(‘username’); echo $this->Form->input(‘password’); echo $this->Form->input(‘password_confirm’); // App specific feature echo $this->Form->input(‘Profile.newsletter’, array( ‘label’ => __(‘Suscribe to our newsletter’, true), ‘type’ => ‘checkbox’)); echo $this->Form->end(__(‘I want to be awesome!’, true)); ?>
  • 18. MODELS <?php App::import(‘Model’, ‘Users.User’); class MyUser extends User { // [...] public $hasOne = array(‘Profile’); // [...] public function __construct($id = false, $table = null, $ds = null) { parent::__construct($id, $table, $ds); $this->validate[‘username’][‘length’] = array( ‘rule’ => array(‘minLength’, 5)); } // [...] public function register($data) { $success = parent::register($data); if ($success) { // Your business logic here } return $success; } // [...] public function foobar() { } } ?>
  • 19. CONTROLLERS <?php App::import(‘Controller’, ‘Users.Users’); class MyUsersController extends UsersController { // [...] public function beforeFilter() { $this->User = ClassRegistry::init('MyUser'); parent::beforeFilter(); $this->Auth->deny('index'); } // [...] public function register() { if (!empty($this->data)) { if ($this->User->register($this->data)) { // Your app specific logic here $this->redirect(‘controller’ => ‘pages’, ‘action’ => ‘display’, ‘welcome’); } } parent::register(); } // [...] public function foobar() { } } ?>
  • 20. TO DO I mp CONTROLLERS rov em e Router::connect( '/users/:action/*', array('plugin' => ‘users’, 'controller' => 'users')); Router::connect( '/users/:action/*', array('plugin' => null, 'controller' => 'my_users')); public function render($action = null, $layout = null, $file = null) { if (is_null($action)) { $action = $this->action; } if ($action !== false) { if (!file_exists(VIEWS . 'my_users' . DS . $action . '.ctp')) { $file = App::pluginPath('users') . 'views' . DS . 'users' . DS . $action . '.ctp'; } } return parent::render($action, $layout, $file); }
  • 21. ... AND IT WORKS WITH EVERYTHING Helpers, Libraries, Components, Behaviors... App::import(‘Behavior’, ‘Comments.Commentable’); class MyCommentable extends Commentable { }
  • 22. TIPS AND TRICKS Serious stuff coming!
  • 23. DON’T TRUST ME! Unless you’ve tried it yourself
  • 24. REUSE EXISTING PLUGINS CakePHP’s main feature is its community CakePackages.com: •548 CakePHP related projects •284 developers
  • 25. KISS Refactor Extend
  • 26. USE OBJECTS ATTRIBUTES // Models $this->alias $this->name $this->displayField $this->primaryKey $this->data[‘User’][‘id’]; // Before $this->data[$this->alias][$this->primaryKey]; // After // Controllers $this->plugin $this->modelClass // MyModel $this->modelKey // my_model $this->name Add attributes to your classes!
  • 27. COMPONENTS ARE THE KEY! Add some magic in your plugins
  • 28. HELPER AUTOLOADING class CommentManager extends Object { public $autoHelper = true; public $helperName = ‘Comments.CommentWidget’; public function beforeRender(Controller $Controller) { if ($this->autoHelper) { $Controller->helpers[] = $helperName; } } }
  • 29. BEHAVIOR AUTOLOADING class CommentManager extends Object { public $autoBehavior = true; public $behaviorName = ‘Comments.Commentable’; public function startup(Controller $Controller) { $Model = $Controller->{$Controller->modelClass}; if ($autoBehavior && !$Model->Behaviors->attached($this->behaviorName)) { $Model->Behaviors->attach($this->behaviorName); } } }
  • 30. AUTODETECTED ACTIONS class CommentManager extends Object { public $autoActions = true; public function startup(Controller $Controller) { if ($autoActions) { if (!empty($Controller->data[‘Comment’])) { // [...] Automatically save the comment $Controller->redirect($Controller->referer()); } } } }
  • 31. AUTO DATA FETCHING class FoobarManager extends Object { public function beforeRender(Controller $Controller) { $data = [...]; // Your logic here to get the correct data for the view $Controller->set(‘data_for_foobar_helper’, $data); } }
  • 32. HELPERS THAT HELP • Reduce PHP code in views • Unique entry point • Deal with elements • Performance optimization
  • 33. ... BEHIND THE SCENE class FoobarHelper extends AppHelper { public function beforeRender() { if (ClassRegistry::isKeySet('view')) { $View = ClassRegistry::getObject('view'); $this->_data = $View->getVar('data_for_foobar_helper'); } } }
  • 34. public function display($element = 'carts/view', $options) { if (!ClassRegistry::isKeySet('view')) { return; } if (empty($cartData)) { if (is_a($this->Session, 'SessionHelper') && $this->Session->check('Cart')) { $cartData = $this->Session->read('Cart'); } else { $cartData = $this->requestAction($this->cartRequestUrl); } } if (empty($cartData)) { trigger_error(__d('cart', 'No cart found.', true), E_USER_NOTICE); } else { // [...] Format the data and add default options (caching...) $options['cartData'] = $cartData; return ClassRegistry::getObject('view')->element($element, $options); } }
  • 35. USE THE CONFIGURE CLASS • With default values • Configure::load() public function __construct($id = false, $table = null, $ds = null) { $userClass = Configure::read('App.UserClass'); if (empty($userClass)) { $userClass = 'User'; } $this->belongsTo['User'] = array( 'className' => $userClass, 'foreignKey' => 'user_id'); // [...] }
  • 36. CALLBACKS / HOOKS class StuffableBehavior extends ModelBehavior { public function doStuff(Model $Model, $id) { if ($Model->isStuffable($id)) { // [...] if (method_exists($Model, ‘afterStuff’)) { $Model->afterStuff(); } } } // Fallback, default logic public function isStuffable(Model $Model, $id) { return true; } }
  • 37. HIGHLIGHT ERRORS Trigger errors for the developer Throw Exceptions for the User $mandatory = Configure::read('Foo.bar'); if (empty($mandatory)) { trigger_error(‘You must configure your Foobar’, E_USER_ERROR); } public function doStuff($id) { $Model->id = $id; if (!$Model->exists($id)) { throw new OutOfBoundsException(__(‘Invalid object’, true)); } }
  • 38. MAKE MIGRATIONS EASY • Version your code, tag versions (KISS, Extend, Refactor) • Document API changes between versions • Use CakeDC’s awesome Migrations plugin! • Schema updates • Initial data • Configuration assistance
  • 39. ... AND ALSO • Write tests • Use __d(‘myplugin’, ‘This is my text’); • Document your code • Provide interfaces to implement (Lib) • Write tests... really!
  • 42. PLUGINS DIRECTORY Reduce plugin duplication “Diversity is good... with moderation” CakePackages.com
  • 43. PLUGIN MANAGER Shell Generic installer Migrations
  • 44. METADATA Version Dependencies Implemented “Interface”
  • 45. QUESTIONS? @pierremartin http://pierre-martin.fr

Editor's Notes

  1. CakePHP-fr now: 15000 messages, 800 members, 500 visitors a day
  2. Adding associations, behaviors Changing redirection, workflow...
  3. Users is something that is common to most of the applications There are common features, but User data / associations / workflow is different across applications
  4. Here is a quick and dirty render overriding allowing you to load parents views if needed
  5. I will introduce some practices I find useful and I learnt when trying to reuse plugins I wrote This is just something personal... so take it as it!
  6. Adding associations, behaviors Changing redirection, workflow...
  7. The keywork here is &amp;#x201C;magic&amp;#x201D;. You can make your plugin easier to integrate in an application by adding some automagical features in a Component attached to Controller that needs it. However, be sure to provide a way to disable this magic if needed.
  8. CakePHP-fr now: 15000 messages, 800 members, 500 visitors a day