SlideShare ist ein Scribd-Unternehmen logo
1 von 45
Downloaden Sie, um offline zu lesen
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

Weitere ähnliche Inhalte

Was ist angesagt?

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
 

Was ist angesagt? (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
 

Ähnlich wie 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
 

Ähnlich wie 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
 

Mehr von 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
 

Mehr von 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
 

Kürzlich hochgeladen

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 

Kürzlich hochgeladen (20)

Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 

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

Hinweis der Redaktion

  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