Best practices for joomla extensions developers

54
Joomla Extensions Development Best Practices Francesco Abeni for GiBiLogic extensions.gibilogic.com

description

This slideshow has been presented at JAndBeyond 2013

Transcript of Best practices for joomla extensions developers

Page 1: Best practices for joomla extensions developers

Joomla Extensions Development Best Practices

Francesco Abeni for GiBiLogicextensions.gibilogic.com

Page 2: Best practices for joomla extensions developers

About me

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

FrancescoAbeni

sPrintAddCSSPizzaBox

Page 3: Best practices for joomla extensions developers

About this speech

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

The quality of code in the Joomlasphere

Page 4: Best practices for joomla extensions developers

No dev course

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 5: Best practices for joomla extensions developers

Our target

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Good = not bad

Excellent = above the average

Good is enough for today

Page 6: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 7: Best practices for joomla extensions developers

IDE basic features

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● multiple files edit● syntax highlighting● index for methods and variables● autocompletion● compiler

● versioning / unit testing / phpdoc / ...

Page 8: Best practices for joomla extensions developers

Some IDEs

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 9: Best practices for joomla extensions developers

Versioning

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

http://git-scm.com/book

Page 10: Best practices for joomla extensions developers

Standard

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 11: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 12: Best practices for joomla extensions developers

Everything in its right place

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Backend ● administrator○ components

■ com_componentname● componentname.php● controllers● models● views

Page 13: Best practices for joomla extensions developers

Everything in its right place

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Backend ● administrator○ components

■ com_componentname● ...● tables● sql● helpers

Page 14: Best practices for joomla extensions developers

● media○ com_componentname

■ css■ js■ img

● components○ com_componentname

■ componentname.php■ controllers■ models■ views

Everything in its right place

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Frontend

● images○ com_componentname

Page 15: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 16: Best practices for joomla extensions developers

CSS / JS

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Use existing libraries

JavaScript● MooTools (since Joomla 1.5)● JQuery (since Joomla 2.5)

CSS + JavaScript● Bootstrap (since Joomla 3.x)

Page 17: Best practices for joomla extensions developers

CSS out of the door

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Don't:<br style="clear: both">

<div style="height: 200px">

Page 18: Best practices for joomla extensions developers

JS out of the door

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<button id="submit" type=submit" value="ClickMe!" onclick="validateForm()" />

Do:<button id="submit" type=submit" value="ClickMe!"/>

document.addEvent('load',function(){ $('submit').addEvent('click',function(){

validateForm(); });

});

Don't:

Page 19: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 20: Best practices for joomla extensions developers

Joomla framework

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● JDatabase● JUser● JSession● JDocument● JHTML● JForm● JFile● JUri

● JFolder● JLog● JFilterInput ● JError and JException● JDate● JUtilities● JVersion● JLayout

Page 21: Best practices for joomla extensions developers

PHP functions and classes

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● pcre● trim● usort● array_map● json_encode● json_decode● microtime(true)● glob

● DateTime● Standard PHP Library● Exception● SimpleXML● TCPDF● PHPMailer

Page 22: Best practices for joomla extensions developers

PHP version

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● 16. Dec 2010: PHP 5.2 end of life● 11. Jul 2013: PHP 5.3 end of life● 01. Mar 2012: PHP 5.4 released ● 20 Jun 2013: PHP 5.5 released

● PHP 5.4 is 40% faster than PHP 5.2

Page 23: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 24: Best practices for joomla extensions developers

Real objects

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

book writer library

Page 25: Best practices for joomla extensions developers

Bad design sample

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● views/search● views/editbook● views/book● views/books● views/booksauthor● views/topten

Don't:

Page 26: Best practices for joomla extensions developers

The controller

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● Filters input● Decides what to do● Checks access● Executes task(s)● Passes control to the view

Page 27: Best practices for joomla extensions developers

The model

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● Retrieves object data● Validates object data● Gets object data● Saves object data● Hates to be mistaken as an helper

Page 28: Best practices for joomla extensions developers

The view

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● Ask the model for data● Display object(s)● Uses layouts!

Page 29: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 30: Best practices for joomla extensions developers

Header comment

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php

/*** @version mybooks.php 2013-08-10 15:23:00Z zanardi* @package GiBi MyBooks* @author GiBiLogic* @authorUrl http://www.gibilogic.com* @authorEmail [email protected]* @copyright Copyright (C) 2013 GiBiLogic. All rights reserved.* @license GNU/GPL v2 or later* @description Backend entry point*/

Page 31: Best practices for joomla extensions developers

Entry point

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php...defined('_JEXEC') or die();

jimport('joomla.application.component.controller');

$view = JFactory::getApplication()->input->get('view', 'book');$task = JFactory::getApplication()->input->get('task', 'index');JFactory::getApplication()->input->set('task', "$view.$task");

$controller = JController::getInstance('MyBooks');$controller->execute($task);$controller->redirect();

Page 32: Best practices for joomla extensions developers

Controller - part 1

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php...defined('_JEXEC') or die('The way is shut!');

jimport('joomla.application.component.controlleradmin');

/*** MyBooksControllerBook class.** @see JControllerAdmin*/class MyBooksControllerBook extends JControllerAdmin{ /** * Controller's view. * * @var JView */ private $view; ...

Page 33: Best practices for joomla extensions developers

Controller - part 2

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... /** * Class constructor. * * @param type $config */ public function __construct($config = array()) { parent::__construct($config);

$this->model = $this->getModel();

$this->view = $this->getView(JFactory::getApplication()->input->get('view', 'book'), 'html'); $this->view->setModel($this->model, true); $this->view->setModel($this->getModel('Author', 'MyBooksModel'), false); $this->view->setModel($this->getModel('Editor', 'MyBooksModel'), false); } ...

Page 34: Best practices for joomla extensions developers

Controller - part 3

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... public function index() { $this->view->setLayout('index') $this->view->display(); }

public function create() { $this->view->setLayout('create'); $this->view->display(); }

public function save() { $data = JFactory::getApplication()->input->get('jform', null); if (!$data || !$this->model->validate($data)) { $msg = 'Invalid data!'; $type = 'error'; $this->setRedirect('index.php?option=com_mybooks&view=book&task=create', $msg, $type); return false; }

Page 35: Best practices for joomla extensions developers

Model - part 1

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php...defined('_JEXEC') or die('The way is shut!');

jimport('joomla.application.component.model');jimport('joomla.html.pagination');

class MybooksModelBook extends JModel{ private $table = '#__mybooks_book';

public function __construct($config = array()) { parent::__construct($config);

$app = JFactory::getApplication(); $limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'), 'int'); $limitstart = $app->input->get('limitstart', 0, '', 'int'); $this->setState('limit', $limit); $this->setState('limitstart', $limitstart); $this->setState('author_id', $app->getUserStateFromRequest('com_mybooks.filters.author_id', 'author_id', 0, 'int')); }

Page 36: Best practices for joomla extensions developers

Model - part 2

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... public function getList() { return $this->_getList( $this->buildQuery(), $this->getState('limitstart'), $this->getState('limit') ); }

public function getLast() { $query = $this->_db->getQuery(true); $query->select('*')->from($this->table)->orderby('created_at DESC'); $this->_db->setQuery($query,0,1); $results = $this->_db->loadObjectList('id'); return $results ? $results : array(); }

public function getLastByAuthor($author_id) { $query = $this->_db->getQuery(true); $query->select('*')->from($this->table)->where(“author_id = '$author_id'”)->orderby('created_at DESC'); $this->_db->setQuery($query,0,1); return $this->_db->loadObject(); }

Page 37: Best practices for joomla extensions developers

Model - part 3

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... public function create($data) { if (!$data) { return 0; }

$data['created_at'] = date('Y-m-d H:i:s');

$query = $this->_db->getQuery(true);

$query->insert($this->table)->columns(array_keys($data))->values(sprintf("'%s'", implode("','", array_values($data)))); $this->_db->setQuery($query);

return false === $this->_db->execute() ? 0 : $this->_db->insertid(); } ...

Page 38: Best practices for joomla extensions developers

Model - part 4

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... public function delete($ids) { $query = $this->_db->getQuery(true); $query->delete()->from($this->table)->where('id IN '.implode(',', $ids)); return false !== $this->_db->execute(); }

public function getPagination(){ return new JPagination( $this->_getListCount($this->buildQuery()), $this->getState('limitstart'), $this->getState('limit') ); }

private function buildQuery(){ $where = $this->buildWhere(); $query = $this->_db->getQuery(true); return $query->select('*')->from($this->table)->where($where)->orderby('created_at DESC'); } ...

Page 39: Best practices for joomla extensions developers

View - part 1

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php...defined('_JEXEC') or die('The way is shut!');

jimport('joomla.application.component.view');

class MyBooksViewBook extends JView{ public function display($tpl = null) { $this->pagination = $this->getModel()->getPagination(); $this->filter_author_id = $this->getModel()->getState('author_id');

$this->books = $this->getModel()->findAll(); $this->authors = $this->getModel('Authors')->getList(); $this->editors = $this->getModel('Editors')->getList();

$this->addToolbar($tpl);

parent::display($tpl); }

Page 40: Best practices for joomla extensions developers

View - part 2

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php ... protected function addToolbar($tpl){ $methodName = 'addToolBar' . ucfirst(!$tpl ? 'default' : $tpl); $this->{$methodName}(); }

private function addToolBarDefault(){ JToolBarHelper::title(JText::_('COM_MYBOOKS') . ': ' . JText::_('COM_MYBOOKS_BOOK_LIST')); JToolBarHelper::addNew('create'); JToolBarHelper::preferences('com_mybooks'); JToolBarHelper::divider(); JToolBarHelper::deleteList('COM_MYBOOKS_BOOK_LIST_DELETE_CONFIRM', 'delete'); }

private function addToolBarCreate(){ JToolBarHelper::title(JText::_('COM_MYBOOKS') . ': ' . JText::_('COM_MYBOOKS_BOOK_NEW')); JToolBarHelper::apply('save'); JToolBarHelper::divider(); JToolBarHelper::back('JTOOLBAR_BACK', 'index.php?option=com_mybooks'); }}

Page 41: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 42: Best practices for joomla extensions developers

Helpers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Common (usually static) functions not related to a specific object

● Get date / time / external info● Format date and numbers● Build title and/or other HTML snippets

Page 43: Best practices for joomla extensions developers

Table classes

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Interface to and from the database

Active Record pattern

● Define table name and unique id● load, store, delete, and so on

Page 44: Best practices for joomla extensions developers

Table classes - sample code

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

<?php

class TableBook extends JTable { public function __construct(&$db) { parent::__construct(‘#__books’, ‘id’, $db); } }

Page 45: Best practices for joomla extensions developers

Layouts

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page types related to a single view (object)"tmpl" subfolder (template override)

● List● Single item (readonly)● Single item (edit form)● Blog● ...

Page 46: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 47: Best practices for joomla extensions developers

System messages

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

$app = JFactory::getApplication();$app->enqueueMessage( $msg, $type )

Page 48: Best practices for joomla extensions developers

JError / JException / JLog

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Error handling vs. logging

● JError is deprecated● JException is deprecated● Use basic PHP Exception class

● JLog is a way to track what's happening

Page 49: Best practices for joomla extensions developers

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 50: Best practices for joomla extensions developers

Visibility

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Variables and methods

● "var ..." is deprecated since PHP 5.1.2● public : available from other classes● private : available only from the class● protected : available from the class and

from inherited or parent classes

Page 51: Best practices for joomla extensions developers

Constants

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● constants instead of variables● drop DS● drop DIRECTORY_SEPARATOR● use Joomla constants:

http://docs.joomla.org/Constants● warning: JPATH_SITE vs JPATH_BASE vs

JPATH_ROOT vs JPATH_ADMINISTRATOR

Page 52: Best practices for joomla extensions developers

Versioning

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

● version format: major.minor.release (es. v3.1.5)● variant: v3.1.5 Free, v3.1.5 Pro

Page 53: Best practices for joomla extensions developers

And the road goes on and on

Francesco Abeni for GiBiLogichttp://extensions.gibilogic.com - [email protected]

Page 54: Best practices for joomla extensions developers

Thanks :)

[email protected]@f_abeni / @gibilogic

http://www.slideshare.net/FrancescoAbeni/best-practices-for-joomla-extensions-developers-25353320

Francesco Abenihttp://extensions.gibilogic.com