Skip to content
Greg Besson edited this page Jun 16, 2013 · 11 revisions

AdfabCore

Google Analytics

Permet l'intégration sur l'ensemble du site de GA. Utilisation du plugin de Jurian Sluiman (http://juriansluiman.nl)

Usage

Un view Helper est disponible. Le code généré est stocké dans un helper de classe Zend\View\Helper\HeadScript, par défaut il s'agit de Zend\View\Helper\InlineScript (donc affichage en bas de page comme préconisé, mais on pourra le modifier pour que ce soit HeadScript ou tout autre helper de la classe HeadScripthelper.

AdfabCore\Analytics\Tracker a pour alias google-analytics dans la configuration du Service Manager. Cet objet est utilisé pour configurer GA. A partir d'un controleur :

public function fooAction ()
{
    $ga = $this->getServiceLocator()->get('google-analytics');

//Désactiver complètement le tracking GA :
$ga->setEnableTracking(false);

// Tracker un event ou une transaction e-commerce mais désactiver seulement le tracking de page :
$ga->setEnablePageTracking(false);

// Tracker un event :
$event = new AdfabCore\Analytics\Event;
$event->setCategory('Videos');
$event->setAction('Play');
$event->setLabel('Gone With the Wind');  // optionnel
$event->setValue(5);                     // optionnel

$ga->addEvent($event);

// Tracker une transaction e-commerce (et lui ajouter des items au format GA):
$transaction = new AdfabCore\Analytics\Ecommerce\Transaction;
$transaction->setId('1234');      // order ID
$transaction->setTotal('28.28');  // total

$item = new SlmGoogleAnalytics\Analytics\Ecommerce\Item;
$item->setPrice('11.99');         // unit price
$item->setQuantity('2');          // quantity

$transaction->addItem($item);

$ga->addTransaction($transaction);
}

Facebook

AdfabCore détecte automatiquement si l'application est appelée depuis Facebook. Si c'est le cas, une session est créée dans le container "Facebook" avec une variable "signed_request" contenant le tableau des valeurs contenues dans la variable signed_request envoyée par FB. Ce tableau contient notamment une information sur le fait que l'utilisateur loggé dans FB est fan de la page ou pas. Il suffit alors dans un contrôleur de regarder la présence de cette variable en cas de besoin :

    // If on Facebook, check if you have to be a FB fan to play the game
	$session = new Container('facebook');
	if ($session->offsetExists('signed_request')) {
		$sr = $session->offsetGet('signed_request');
		if($sr['page']['liked'] == 1){

			return true;
		}
	}

	return false;

CKEditor

Met à disposition un view Helper permettant l'usage d'un bloc WysiWig ckeditor.

Usage

Au niveau de la vue d'un élément de type TEXTAREA par exemple, dont l'ID est "id_de_mon_textarea" :

<?php echo $this->formTextarea($form->get('content')) . $this->formElementErrors($form->get('content')) ?>
<?php $this->QgCKEditor(
	'block_content',
    array(
    	'BasePath' => $this->basePath('js/lib/ckeditor'),
        'Width' => "100%",
        'Height' => "340",
        'filebrowserBrowseUrl' => '/elfinder', // eg. 'includes/elFinder/elfinder.html'
        'uiColor' => '#9AB8F3',
        //'Color' => "#000",
        'Toolbar'=> array(
        	array('Source','Maximize'),
            array('Templates','Styles','Format'),
            array('Bold','Italic','Underline','Subscript','Superscript'),
            array('NumberedList','BulletedList','Outdent','Indent'),
            array('JustifyLeft','JustifyCenter','JustifyRight'),
            array('Link','Unlink'),
            array('Image','Table')
        )
    )
);?>

Il est donc possible de configurer à la volée les options de CKEditor pour un bloc déterminé.

Afin de créer une configuration par défaut, il suffira de configurer le fichier de config adfabcore.local.php en conséquence :

'ckeditor' => array(
    'BasePath' =>'js/lib/ckeditor', // Require!!
    'Width'      => "100%",
    'Height'     => "340",
    'Language'   => 'fr',
    'Color'      => '#F7F7F7',
    'stylesSet'  => 'custom_styles:/js/admin/ckeditor-styles.js',
    'templates_files'  => array('/js/admin/ckeditor-templates.js'),
    'contentsCss'  => array('/css/ckeditor-css.css'),

    // Full toolbars
    'Toolbar'    => array(
        array('Source','-','DocProps','Preview','Print'),
        array('Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo'),
        array('Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt'),
        array('Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField'),
        '/',
        array('Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat'),
        array('NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote,'CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl'),
        array('Link','Unlink','Anchor' ),
        array('Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'),
        '/',
        array('Styles','Format','Font','FontSize'),
        array('TextColor','BGColor' ),
        array('Maximize', 'ShowBlocks','-','About'),
    ),
    'ElFinderBaseURL'      => '/elfinder/ckeditor',
    'ElFinderWindowWidth'  => "1000",
    'ElFinderWindowHeight' => "650",
),

Exemple de résultat obtenu :

ELFinder

Afin de complèter efficacemement CKEditor, AdfabCore propose le module ELFinder qui permet une gestion des fichiers sur le serveur, là aussi en mode wysiwyg. A noter la configuration ci-dessus pour CKEditor afin que CKEditor fasse usage de ELFinder :

'ElFinderBaseURL'      => '/elfinder/ckeditor',
'ElFinderWindowWidth'  => "1000",
'ElFinderWindowHeight' => "650",

La configuration d'accès aux répertoires accessibles à ELFinder se réalise dans adfabcore.local.php :

'QuConfig' => array(
    'QuElFinder'=>array(
        'QuRoots'=>array(
            'driver'        => 'LocalFileSystem',
            'path'          =>  'C:\programmation\www\playground\public\uploads\files',
            'URL'           =>  '/uploads/files/',
            'accessControl' => 'access'
        ),
        'BasePath'=>'/js/lib/elfinder',
    ),
),

` Exemple de résultat obtenu :

Cron

AdfabCore met à disposition un outil complet de planification et exécution de services CRON. Le point d'accès est centralisé et usage est fait du pattern Observer afin de permettre à TOUT module désireux d'exposer un service CRON de le faire simplement et sans adhérence.

Afin qu'un module puisse inscrire un service de CRON, il suffit de paramétrer ceci dans la méthode onBootstrap de Module.php du module en question :

$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Application','getCronjobs', array($this, 'addCronjob'));

La méthode addCronjob donnant ça :

/**
 * This method get the cron config for this module an add cronjobs to the listener
 *
 * @param  EventManager $e
 * @return array
 */
public function addCronjob($e)
{
    $cronjobs = $e->getParam('cronjobs');

	// Toutes les 15 minutes
    $cronjobs['adfagame_email'] = array(
        'frequency' => '*/15 * * * *',
        'callback'  => '\AdfabGame\Service\Game::cronMail',
        'args'      => array('bar', 'baz'),
    );

    // tous les jours à 5:00 AM
    $cronjobs['adfagame_instantwin_email'] = array(
        'frequency' => '* 5 * * *',
        'callback'  => '\AdfabGame\Service\Cron::instantWinEmail',
        'args'      => array(),
    );

    return $cronjobs;
}

Un cronjob est donc défini par 'frequency' qui définit dans le même format qu'un cron normal les temps de passage du cron, 'callback' qui est le service appelé et 'args' qui contient un tableau d'arguments (ATTENTION : Si aucun argument ne doit être passé, args doit avoir un tableau vide assigné (cf. ci-dessus))

Afin que le service puisse s'exécuter, nous allons devoir "bootstraper" l'environnement, car celui-ci n'est pas dispo quand le service est appelé :

public static function instantWinEmail()
{
    $configuration = array(
            'modules' => array(
                    'Application',
                    'DoctrineModule',
                    'DoctrineORMModule',
                    'ZfcBase',
                    'ZfcUser',
                    'BjyAuthorize',
                    'ZfcAdmin',
                    'AdfabCore',
                    'AdfabUser',
                    'AdfabCms',
                    'AdfabReward',
                    'AdfabGame',
                    'AdfabPartnership'
            ),
            'module_listener_options' => array(
                'config_glob_paths'    => array(
                    'config/autoload/{,*.}{global,local}.php',
                ),
                'module_paths' => array(
                    './module',
                    './vendor',
                ),
            ),
    );

    $smConfig = isset($configuration['service_manager']) ? $configuration['service_manager'] : array();
    $sm = new \Zend\ServiceManager\ServiceManager(new \Zend\Mvc\Service\ServiceManagerConfig($smConfig));
    $sm->setService('ApplicationConfig', $configuration);
    $sm->get('ModuleManager')->loadModules();
    $sm->get('Application')->bootstrap();

    $mailService = $sm->get('adfabuser_message');
    $gameService = $sm->get('adfabgame_instantwin_service');
    $options = $sm->get('adfabgame_module_options');

    $from    = "admin@playground.fr";//$options->getEmailFromAddress();
    $subject = "Votre jeu Instant gagnant ClubMetro"; //$options->getResetEmailSubjectLine();

    // Je recherche les jeux instantwin en cours
    $games = $gameService->getActiveGames(false, 'instantwin');

    // Je recherche les joueurs qui ont deja joué une seule fois au jeu mais pas rejoué dans le laps autorisé
    $arrayUsers = array();
    foreach ($games as $game) {
        $entries = $gameService->getEntryMapper()->findPlayersWithOneEntryBy($game);
        foreach ($entries as $e) {
            $arrayUsers[$e->getUser()->getId()]['user'] = $e->getUser();
            $arrayUsers[$e->getUser()->getId()]['game'] = $game;
        }
    }

    // J'envoie un mail de relance
    foreach ($arrayUsers as $k => $entry) {
        $user = $entry['user'];
        $game = $entry['game'];
        $message = $mailService->createHtmlMessage($from, $user->getEmail(), $subject, 'adfab-game/frontend/email/game_instantwin_reminder', array('game' => $game, 'user' => $user));
        $mailService->send($message);
    }
}

Une fois l'application "bootstrappée" (jusqu'à la ligne 34), tous les outils sont à notre disposition pour réaliser nos services.

ShortenUrl

Un service de "racourcissement d'URL" est mis à disposition via un plugin de contrôleur. Il est souvent utilisé dans le cas de partages Facebook ou Twitter. AdfabCore utilise Bit.ly pour réaliser cette fonctionnalité.

Usage

// Dans une action de contrôleur
// L'URL complète normale de l'application
$socialLinkUrl = $this->url()->fromRoute('lottery', array('id' => $game->getIdentifier()), array('force_canonical' => true));

// With core shortener helper
$socialLinkUrl = $this->shortenUrl()->shortenUrl($socialLinkUrl);

MailService

AdfabCore met à disposition un service d'envoi de mail. Plus besoin de se préoccuper de cette fonctionnalité, il est possible simplement d'envoyer des mails au format texte ou html en s'appuyant sur la config de adfabcore.local.php, et en bénéficiant de la fonctionnalité de templating des mails.

Usage

Configuration de l'envoi des mails : Dans adfabcore.local.php

'transport_class' => 'Zend\Mail\Transport\File',
'options_class' => 'Zend\Mail\Transport\FileOptions',
'options' => array(
    'path'              => 'data/mail/',
    'callback'  => function (\Zend\Mail\Transport\File $transport) {
        return 'Message_' . microtime(true) . '_' . mt_rand() . '.txt';
    },
),

Cette configuration permettra pour les développeurs de ne pas envoyer les mails, mais plutôt de les enregistrer dans un répertoire local, facilitant le développement.

/**
 * Email transport
 *
 * Name of Zend Transport Class to use
 */
'transport_class' => 'Zend\Mail\Transport\Smtp',
'options_class' => 'Zend\Mail\Transport\SmtpOptions',
'options' => array('host'=> '127.0.0.1',),

Cette configuration est classique pour envoyer des mails, avec un relais SMTP en local.

/**
 * Email transport
 *
 * Name of Zend Transport Class to use
 */
'transport_class' => 'Zend\Mail\Transport\Smtp',
'options_class' => 'Zend\Mail\Transport\SmtpOptions',
'options' => array(
    'name'              => 'email-smtp.us-east-1.amazonaws.com',
    'host'              => 'email-smtp.us-east-1.amazonaws.com',
    'port'              => 465,
    'connection_class'  => 'login', // ou 'plain'
    'connection_config' => array(
        'username' => 'AKIAJWGCCZATEWLGYE5A',
        'password' => 'EEeeeeefhflhlsdlvndlvnerlgne',
        'ssl'      => 'ssl', // can use tls or ssl
    ),
),

Cette configuration typique d'un serveur AWS illustre la config d'un serveur sécurisé uilisant SSL.

Afin d'envoyer un mail, il suffira d'instancier le service de cette manière :

$mailService = $this->getServiceManager()->get('adfabgame_message');
$message = $mailService->createHtmlMessage($from, $to, $subject, 'adfab-game/frontend/email/template.phtml', array('game' => $game, 'skinUrl' => $skinUrl));
$mailService->send($message);

exemple :

public function sendGameMail($game, $user, $template = 'postvote')
{
    $mailService = $this->getServiceManager()->get('adfabgame_message');
    $from 		 = 'sender@test.com';
    $to          = $user->getEmail();
	$subject 	 = 'Club Metro';
    $renderer 	 = $this->getServiceManager()->get('Zend\View\Renderer\RendererInterface');
    $skinUrl 	 = $renderer->url('home', array(), array('force_canonical' => true));
    $config 	 = $this->getServiceManager()->get('config');

    if (isset($config['contact']['email'])) {
        $from = $config['contact']['email'];
    }

    $message = $mailService->createHtmlMessage($from, $to, $subject, 'adfab-game/frontend/email/'.$template, array('game' => $game, 'skinUrl' => $skinUrl));
    $mailService->send($message);
}

A noter l'astuce :

$renderer 	 = $this->getServiceManager()->get('Zend\View\Renderer\RendererInterface');
$skinUrl 	 = $renderer->url('home', array(), array('force_canonical' => true));

qui permet de créer l'url de base de l'application et de la passer dans le model du mail afin de faciliter l'affichage des images notamment.

Slugify

Cette fonctionnalité permet de transformer du texte en "slug" utilisable dans une url, à la manière de Wordpress. Elle est proposée sous forme de filtre de formulaire.

usage

$inputFilter->add($factory->createInput(array(
            'name' => 'identifier',
            'required' => true,
            'filters' => array(
                array(
                    'name' => 'StripTags'
                ),
                array(
                    'name' => 'StringTrim'
                ),
                array(
                    'name' => 'AdfabCore\Filter\Slugify'
                )
            ),
            'validators' => array(
                array(
                    'name' => 'StringLength',
                    'options' => array(
                        'encoding' => 'UTF-8',
                        'min' => 3,
                        'max' => 255
                    )
                )
            )
        )));

Ce filtre permet de transformer par exemple "ceci est un texte d'essai" en "ceci-est-un-texte-d-essai"

##Les layouts La configuration du layout global de l'application se déclare dans le respect de ZF2. Sur ce Framework, nous le faisons au niveau du module application :

'template_map' => array(
    'layout/layout'           => __DIR__ . '/../view/layout/2columns-right.phtml',
    'layout/1column'           => __DIR__ . '/../view/layout/1column.phtml',
    'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
    'error/404'               => __DIR__ . '/../view/error/404.phtml',
    'error/index'             => __DIR__ . '/../view/error/index.phtml',
),

Nous retrouvons les layouts qui seront utilisés sur tout le framework.

Afin d'assigner des layout différents suivant nos pages, il suffit de créer une configuration 'core_layout' dans n'importe quel config de module ou fichier de config autoload. Nous préconisons de définir les layout au niveau de chacun des modules afin de respecter la séparation des responsabilités.

Voici un exemple de configuration de layout sur le module Game :

return array(
'core_layout' => array(
	'AdfabGame' => array(
		'default_layout' => 'layout/2columns-right',
		'controllers' => array(
			'adfabgame'   => array(
				'default_layout' => 'layout/1column',
				'actions' => array(
					'index' => array(
						'default_layout' => 'adfabgame/layout/2columns-left',
					)
				),
			),
		),
	),
),
)

Il est tout d'abord possible de définir un layout spécifique pour l'ensemble d'un module. Il suffira de renseigner l'entrée 'default_layout' du module. Ex. :

return array(
'core_layout' => array(
	'AdfabGame' => array(
		'default_layout' => 'layout/2columns-right',
	),
),
)

Ainsi, toutes les pages du module Game utiliserons le layout 2columns-right (qui est défini dans le module application).

On peut ensuite associer des layouts spécifiques pour certains controllers du module. Ex. :

return array(
'core_layout' => array(
	'AdfabGame' => array(
		'default_layout' => 'layout/2columns-right',
		'controllers' => array(
			'adfabgame'   => array(
				'default_layout' => 'layout/1column',
			),
		),
	),
),
)

Ainsi, toutes les pages du module Game utiliserons le layout 2columns-right (qui est défini dans le module application) sauf les pages gérées par le controller "adfabgame" qui elles adopteront le layout 1column (lui aussi défini dans application).

Enfin, il est possible de spécialiser un layout pour une action. Ex. :

return array(
'core_layout' => array(
	'AdfabGame' => array(
		'default_layout' => 'layout/2columns-right',
		'controllers' => array(
			'adfabgame'   => array(
				'default_layout' => 'layout/1column',
				'actions' => array(
					'index' => array(
						'default_layout' => 'adfabgame/layout/2columns-left',
					)
				),
			),
		),
	),
),
)

Ainsi, toutes les pages du module Game utiliserons le layout 2columns-right (qui est défini dans le module application) sauf les pages gérées par le controller "adfabgame" qui elles adopteront le layout 1column (lui aussi défini dans application), à l'exception de l'action "index" qui elle profitera du layout adfabgame/layout/2columns-left.

A noter que ce layout est défini dans le module Game ! Ce qui signifie que l'on peut donc déclarer des layouts spécifiques à un module. Pour cela, ne pas oublier de déclarer où se trouve ce layout dans la config du module :

'template_map' => array(
    'adfabgame/layout/2columns-left' => __DIR__ . '/../view/layout/2columns-left.phtml',
),

Je vous laisse imaginer la souplesse qu'un tel système procure...

Afin de conserver une vision claire des emplacements des layouts, je préconise de préfixer les layouts se trouvant dans un module spécifique par le nom de ce module. Exemple dans le cas ci-dessus : Le layout 2columns-left est préfixé par adfabgame : 'adfabgame/layout/2columns-left'

Les templates de bloc structurels

Une fois un layout défini, celui contient des blocs structurels afin d'organiser la page. On retrouve presque systématiquement les blocs structurels suivants :

  • Head : Il contiendra les meta ainsi que les appels js, css etc...
  • Header : L'entête du site qui est souvent conservé sur toutes les pages. Il contient le logo de la société, le menu, etc...
  • Content : C'est le contenu principal, qui varie de page en page.
  • Footer : Il contient souvent des liens vers les page légales, des raccourcis etc...
  • Colonne de droite : Quand le layout possède une colonne à droite
  • Colonne de gauche : Quand le layout possède une colonne à gauche
  • Autres : Et suivant les besoins, d'autres blocs peuvent être nécessaires suivant le sites.

Le système de templating avancé du Core permet de définir les templates qui seront associés à ces blocs structurels. En effet, la responsabilité des les "enrichir" est rarement celle du controleur appelé qui se concentre sur le bloc "content". On va donc proposer de définir le contenu et l'apparence des blocs structurels par configuration.

Ce système permet la définition des templates de bloc en cascade, comme on va le voir.

Voici un exemple de configuration complet, nous allons le détailler par la suite :

'core_layout' => array(
'AdfabGame' => array(
	'default_layout' => 'layout/1column',
	'children_views' => array(
		'col_right'  => 'adfab-game/layout/col-right/index.phtml',
		'col_left'	 => 'adfab-game/layout/col-left/index.phtml',
		'footer'     => 'adfab-game/layout/footer/index.phtml',
	),
	'controllers' => array(
		'adfabgame'   => array(
			'default_layout' => 'layout/1column',
			'children_views' => array(
				'col_right'  => 'adfab-game/layout/col-right/adfabgame.phtml',
				'header'	=> 'adfab-game/layout/header/adfabgame.phtml'
			),
			'actions' => array(
				'index' => array(
					'default_layout' => 'layout/2columns-right',
					'children_views' => array(
						'col_right'  => 'adfab-game/layout/col-right/adfabgame-intro.phtml',
					),
				)
			)
		),
	),
),
),

Vous reconnaissez la partie des définition de layout vue dans le chapitre précédent. 'children_views' apparait ici. C'est ce qui nous permet de définir des templates pour nos blocs.

On peut d'abord définir des vues spécifiques au niveau d'un module :

'core_layout' => array(
'AdfabGame' => array(
	'default_layout' => 'layout/3columns',
	'children_views' => array(
		'col_right'  => 'adfab-game/layout/col-right/index.phtml',
		'col_left'	 => 'adfab-game/layout/col-left/index.phtml',
		'footer'     => 'adfab-game/layout/footer/index.phtml',
	),
),
),

Ici, je définis 3 templates de blocs :

  • col_right : adfab-game/layout/col-right/index.phtml
  • col_left : adfab-game/layout/col-left/index.phtml
  • footer : adfab-game/layout/footer/index.phtml Cela signifie que pour toutes les pages du module Game, les blocs de droite, de gauche et le footer auront un template spécifique.

A noter ici que nous avons défini ces templates parce que le layout du module est de type 3columns. Il est donc pertinent de définir des templates pour les colonnes de gauche et de droite.

Imaginons maintenant que je souhaite une présentation spéciale pour un controleur de Game :

'core_layout' => array(
'AdfabGame' => array(
	'default_layout' => 'layout/1column',
	'children_views' => array(
		'col_right'  => 'adfab-game/layout/col-right/index.phtml',
		'col_left'	 => 'adfab-game/layout/col-left/index.phtml',
		'footer'     => 'adfab-game/layout/footer/index.phtml',
	),
	'controllers' => array(
		'adfabgame'   => array(
			'default_layout' => 'layout/2columns-right',
			'children_views' => array(
				'col_right'  => 'adfab-game/layout/col-right/adfabgame.phtml',
				'header'	=> 'adfab-game/layout/header/adfabgame.phtml'
			),
		),
	),
),
),

Je me retrouve comme précédemment avec mes 3 blocs définis au niveau du module Game. Mais pour les pages gérées par le controleur adfabgame, nous sommes passés à un layout 2columns-right et nous assignons à la colonne de droite un template spécifique à ce controleur. De même, nous définissons un template spécifique pour le header, pour chacune des pages de ce controleur donc.

A noter que le template du footer défini au niveau du module est bien assigné au controleur.

A noter aussi que le template de la colonne de gauche défini au niveau du module ne sera pas utilisé par ce layout, puisqu'il ne contient pas de colonne de gauche.

Enfin, je souhaite qu'une page gérée par l'action 'index' soit spécifiquement chartée :

'core_layout' => array(
'AdfabGame' => array(
	'default_layout' => 'layout/1column',
	'children_views' => array(
		'col_right'  => 'adfab-game/layout/col-right/index.phtml',
		'col_left'	 => 'adfab-game/layout/col-left/index.phtml',
		'footer'     => 'adfab-game/layout/footer/index.phtml',
	),
	'controllers' => array(
		'adfabgame'   => array(
			'default_layout' => 'layout/1column',
			'children_views' => array(
				'col_right'  => 'adfab-game/layout/col-right/adfabgame.phtml',
				'header'	=> 'adfab-game/layout/header/adfabgame.phtml'
			),
			'actions' => array(
				'index' => array(
					'default_layout' => 'layout/3columns',
					'children_views' => array(
						'col_right'  => 'adfab-game/layout/col-right/adfabgame-intro.phtml',
					),
				)
			)
		),
	),
),
),

On voit que le layout par défaut est à nouveau 3 columns. Le template de sa colonne de gauche sera héritée de la définition au niveau du module. Celui du header est celui défini au niveau du contrôleur. Et la colonne de droite possèdera le template spécifique 'adfab-game/layout/col-right/adfabgame-intro.phtml'

Utilisation de ces templates dans les layout

Voici comment dans un layout, on utilise la définition de ces templates :

<html xmlns="http://www.w3.org/1999/xhtml" lang="fr">
<head>
    <?php echo $this->head(array(
    	'template' => $this->head,
     ));?>
</head>
<body>
	<div id="container">
		<div id="content" class="row-fluid">
			<?php echo $this->header(array(
	        	'template' => $this->header,
	         ));?>
            <div id="homepage">
                <div class="row-fluid">
                	<div class="content-inner span8">
                		<?php echo $this->content; ?>
                	</div>
                	<?php echo $this->column_right(array(
                		'template' => $this->col_right,
                	)); ?>
                </div>
            </div>
            <?php echo $this->footer(array(
	        	'template' => $this->footer,
	         ));?>
        </div>
    </div>
</body>
</html>

Il suffit donc d'injecter la variable de bloc au moment de l'appel de ce bloc comme par exemple pour header :

<?php echo $this->header(array(
'template' => $this->header,
));?>

Quand on appelle le bloc structurel header, on définit la variable 'template' avec $this->header. Cela suffit à propager la configuration

Conclusion

Ce paramétrage de la structure d'un site sur cette plateforme permet une liberté totale pour définir la structure de son site en descendant à un niveau de granularité de la page.

Doctrine

LargeTablePaginator

Ce paginator hérite de celui de Doctrine, il permet notamment de faire un COUNT plus simple (uniquement dans le cas où les tables le permettent) et évite ainsi la création de tables temporaires (phénomène qui arrive avec le SQL imbriqué de la requête de comptage du paginator Doctrine, ou encore des jointures avec ordonnancement).

usage

use Zend\Paginator\Paginator;
use DoctrineORMModule\Paginator\Adapter\DoctrinePaginator as DoctrineAdapter;
use AdfabCore\ORM\Pagination\LargeTablePaginator as ORMPaginator;

 class AdminController extends AbstractActionController
 {
   public function listAction()
   $role     = $this->getAdminUserService()->getRoleMapper()->findByRoleId($roleId);
   $adapter = new DoctrineAdapter(new ORMPaginator($this->getAdminUserService()->getQueryUsersByRole($role, $filter, $search)));
   $paginator = new Paginator($adapter);
   $paginator->setItemCountPerPage(100);
   $paginator->setCurrentPageNumber($this->getEvent()->getRouteMatch()->getParam('p'));
   ...