Lithium

the most RAD framework for PHP 5.3+

Agenda

Disclaimer

omg wtf bbq

Lithium is

What I think it is…

Why?

People numbers

  Lithium Symfony 2
License BSD MIT
Devs ~80 ~425
kLOC ~90 ~750

dive

Dive

$ git clone https://github.com/UnionOfRAD/framework.git webmardi
$ cd webmardi
$ git submodule init && git submodule update
$ chmod -R 0777 app/resources

app/webroot/index.php

<?php

require dirname(__DIR__) . '/config/bootstrap.php';

// return a lithium\action\Response
echo lithium\action\Dispatcher::run(new lithium\action\Request());
    

Bootstrap

<?php
define('LITHIUM_APP_PATH', dirname(dirname(__DIR__)));
define(
  'LITHIUM_LIBRARY_PATH',
  dirname(LITHIUM_APP_PATH) . '/libraries'
);

include LITHIUM_LIBRARY_PATH . '/lithium/core/Libraries.php';

use lithium\core\Libraries;

Libraries::add('lithium');
Libraries::add('app', array('default' => true));

Dispatcher::run()

app/config/routes.php

<?php

use lithium\net\http\Router;

// MongoDB specific id
Router::connect(
    '/{:controller}/{:action}/{:id:[0-9a-f]{24}}.{:type}',
    array('id' => null)
);
Router::connect('/{:controller}/{:action}/{:id:[0-9a-f]{24}}');

Router::connect('/{:controller}/{:action}/{:args}');
    

app/controllers/PagesController.php

<?php

namespace app\controllers;

class PagesController extends \lithium\action\Controller {

    public function view() {
        $message = 'Hello World!';
        return compact('message');
    }
}

app/view/pages/view.html.php


<?php
$this->title($message);
?>
<h1><?= $this->title() ?></h1>
<p>indeed!</p>
    

Short tags?

<?= $foo ?>

// means

<?php echo $h($foo) ?>

// $h() is

<?php echo htmlspecialchars((string) $data, ENT_QUOTES, $encoding) ?>

app/view/layouts/default.html.php

<!DOCTYPE html>
<html>
    <meta charset=utf-8>
    <title><?= $this->title() ?></title>

    <?= $this->content() ?>
</html>
    

MVC

Model!

app/models/Users.php

<?php

namespace app\models

class Users extends \lithium\data\Model {

}

app/config/bootstrap/connections.php

<?php

use lithium\data\Connections;

Connections::add('default', array(
  'host'     => 'localhost',
  'type'     => 'MongoDb',
  'database' => 'my_app',
)));

find

<?php
Users::find(1); // or mongo id

Users::findByEmail('yoan.blanc@gmail.com');

Users::find(array(
  'conditions' => array(
    'email' => 'yoan.blanc@gmail.com'  
  )
);

superhero

app/models/Users.php

<?php

namespace app\models

class Users extends \lithium\data\Model {

  public $validates = array(
    'email' => array(
      array('notEmpty', 'message' => 'is required'),
      array('email', 'message' => 'not a valid e-mail'),
    ),
  );

  public function fullname($entity) {
    return $entity->firstname . ' ' . $entity->lastname;
  }
}

Advanced config

<?php

use lithium\data\Connections;

Connections::add('default', array(
  true => array(
    'type' => 'MongoDb',
    'host' => 'localhost'
  ),
  'production' => array(
    'database' => 'my_app'
  ),
  'development' => array(
    'database' => 'my_app_dev'
  ),
  'test' => array(
    'database' => 'my_app_test'
  )
));

app/config/boostrap/libraries.php

PSR-0 FTW!

<?php

use lithium\core\Libraries;

Libraries::add('Imagine', array(
  'prefix' => 'Imagine\\',
  'path' => LITHIUM_LIBRARY_PATH . '/Imagine/lib/Imagine',
));
Libraries::add('zf2', array(
  'prefix' => 'Zend\\',
  'path' => LITHIUM_LIBRARY_PATH . '/zf2/library/Zend',
));
    

Plugins

Filters, Monkeypatching

or Aspect-Oriented Programming (AOP)

<?php

use lithium\action\Dispatcher;

Dispatcher::applyFilter('run', function($self, $params, $chain) {
  xhprof_enable();
  $data = $chain->next($self, $params, $chain);
  $xhprof_data = xhprof_disable();

  // save the $xhprof_data

  return $data
});
	

QDéfi

QoQa.ch

et famille

QoQa2

QoQa3

Multishop architecture

schema

Templates for everything

Multilingual strings

<!DOCTYPE html>
    <meta charset=utf-8>
    <title><?= $t('Hello World!') ?></title>

    <p><?=$t('We live in Switzerland after all!' ) ?></p>
    <p><?=$tn(
        '{:count} visitor',
        '{:count} visitors',
        $count
    ) ?></p>
</html>

Using .po files but not gettext directly

Multilingual views

<?php
use lithium\net\http\Media;

Media::type('html', 'text/html', array(
  'view'   => 'lithium\\template\\View',
  'paths'  => array(
    'template' => array(
      '{:library}/views/{:controller}/{:template}.{:locale}.{:type}.php',
      '{:library}/views/{:controller}/{:template}.{:type}.php',
    ),
    'layout'   => array(
      '{:library}/views/layouts/{:layout}.{:locale}.{:type}.php',
      '{:library}/views/layouts/{:layout}.{:type}.php',
    ),
    …
  ),
));

cont.


1. /qoqa.ch/views/spam/foo.fr.html.php

2. /qoqa.ch/views/spam/foo.html.php

3. /libraries/qshop/views/spam/foo.fr.html.php

4. /libraries/qshop/views/spam/foo.html.php

Filters

<?php

use lithium\g11n\Message;

Message::applyFilter('_translated', function($self, $params, $chain) {
  $tr = $chain->next($self, $params, $chain);
  if (is_null($tr)) {
    trigger_error(
      'Translation not found '.$params['locale'].': '.$params['id']
    );
  }
  return $tr;
});

Cache

<?= $this->view()->render(
  array('element' => 'offer/deal'),
  compact('deal', 'offer', 'locale'),
  array(
    'cache' => '+5 minutes',
    'key' => $deal->id,
  )
) ?>

template, controller and custom levels.

And many more

ask your questions now!

The End

Many thanks!

Wanted

webdev » jobs@qoqa.com