Introduction

AcidFarm est un framework PHP développé par ACID-Solutions.

Il fonctionne sur un principe de « modules », ces derniers reflétant généralement la structures de vos tables en base de données SQL.

Pouvant tant bien fonctionner en mode « Full Stack » ou en mode « Glue », ce framework met à votre disposition des outils visant à faciliter la réalisations de vos sites et utilitaires destinés à une plateforme web.

La principale qualité d'Acidfarm se situe dans son interface d'administration pré-générée qui permet au développeur de se concentrer sur la partie FrontEnd du site.

Prérequis

AcidFarm se veut accessible aux types d'hébergements les plus classiques.

Aussi, ses restrictions techniques sont assez faibles.

  • PHP 5.3 ou plus
  • Base de données Sql
  • Environement Apache avec RewriteEngine

Configuration de la base de données

Il est nécessaire de configurer votre base de données avant de vous lancer dans la configuration du framework.

Les outils de gestion SQL étant basés sur la classe objet PDO, vous êtes par conséquent libres de travailler avec un type de base assez vaste.

Installation

Les fichiers sources sont accessibles sur Github à cette adresse : https://github.com/ACID-Solutions/acidfarm.

Une fois déposés sur le serveur, il ne reste plus qu'à ouvrir le fichier index.php dans un navigateur web.

Vous serez alors invité à vous rendre sur l'installateur, qui vous demandera les informations nécessaires à la configuration de votre site.

Globalement, l'installation effectue des opérations reproductibles manuellement :

  • Création du fichier sys/server.php recevant les diverses configurations serveur
  • Création des fichiers ou dossiers ignorés par git (files, upload, logs, stats, etc.)
  • Initialisation de la base de données avec les fichiers sql présents dans sys/db
  • Génération du fichier .htaccess à la racine et celui du dossier rest/

Avant de développer

Avant de modifier le site, il est préférable de d'abord installer la base acidfarm dans son univers de développement, puis d'y apporter ses modifications.

Préparation

Acidfarm dispose de quelques script php pouvant vous faciliter la vie. Ces derniers sont disponibles en mode PHP-CLI dans le dossier sys/script/.

Le script sys/script/class_from_table.php vous permettra par exemple de pré-générer vos modules en fonction de votre base de données.

Aussi, une fois le conception de votre site définie, il est donc préférable d'entamer par la création de vos tables SQL. Nous vous invitons, par ailleurs, à conserver les commandes SQL utilisées dans un fichier sql que nous pourrons utiliser plus tard dans un script d'initialisation.

Quand votre base de données sera prête, vous pourrez utiliser la commande suivante :

cd monsite/sys/script/
php class_from_table.php -c -t all -p acid_

Le dossier monsite/sys/script/class/ sera alors créé
Nous partons du principe que le préfixe utilisé est acid_, pour plus de détails, se rendre dans la section Scripts

  • Le contenu du fichier _includer.txt est destiné à être intégré au fichier sys/includes.php (attention aux doublons).
  • Le contenu du fichier _lang.txt est destiné à être intégré dans les fichiers de langue (par exemple, créer un fichier sys/lang/module_fr.php est y intégrer son contenu).
  • Les fichiers php peuvent être placés dans le dossier sys/modules/ (attentions aux modules déjà existants)

Vous disposez d'une base pratique pour commencer.

Architecture

Fonctionnement et Configuration

Le coeur d'Acidfarm ainsi que votre site seront régis par différentes configurations préconçues ou encore à developper toutes stockées dans des tableaux de configuration php.

Acid

Dans nos standards, la variable globale $acid (ou $_GLOBALS['acid']) receuillera les configurations liées à Acidfarm.

C'est le cas :

  • du thème utilisé : $acid['theme']
  • du dossier root d'acidfarm : $acid['folder']
  • du dossier root du site : $acid['url']['folder']
  • l'email de l'adminsitrateur : $acid['admin']['email']
  • et de bien nombreuses autres variables pour la plupart initialisées dans le dossier acid/config.php

Des helper nous permettent d'interagir avec cette variable plus facilement :

echo Acid::get('url:folder'); // echo $GLOBALS['acid']['url']['folder']

Acid::set('url:folder','/'); // $GLOBALS['acid']['url']['folder'] = '/';

if (Acid::exist('url:folder')) { echo 'folder ok'; } // if (isset($GLOBALS['acid']['url']['folder'])) { echo 'folder ok'; }

AcidConf

La variable globale $acidconf (ou $_GLOBALS['acidconf']) receuillera les configurations liées à votre site, au plus généralement, ses particularités par rapport à une installation standard.

C'est le cas :

  • de la configuration du formulaire de contact : $acidconf['contact']['shield']
  • des identifiants de pages réservés: $acidconf['keys']['reserved']
  • des catégories de pâges : $acidconf['page']['categories']
  • et de bien nombreuses autres variables pour la plupart initialisées dans le dossier sys/config.php ou sys/dynamic.php

Des helper nous permettent d'interagir avec cette variable plus facilement :

echo Conf::get('contact:shield'); // echo $GLOBALS['acidconf']['contact']['shield']

Conf::set('contact:shield',true); // $GLOBALS['acidconf']['contact']['shield'] = '/';

if (Conf::exist('contact:shield')) { echo 'contact ok'; } // if (isset($GLOBALS['acidconf']['contact']['shield'])) { echo 'contact ok'; }

HTML

Dans le fichier sys/stop.php, nous recupérons le contenu de la variable globale $html (ou $_GLOBALS['html']) pour l'afficher.

Des helper nous permettent d'interagir avec cette variable plus facilement :

Conf::setContent('hello'); // $GLOBALS['html]' = 'hello';

Conf::addToContent(' world'); // $GLOBALS['html]' .= ' world';

echo Conf::getContent(); // echo $GLOBALS['html'];

Utilisation

Il faut noter que, pour des raisons de maintenabilité, il N'EST PAS D'USAGE DE MODIFIER le contenu du dossier acidfarm (par défaut acid/). Tout est prévu pour écraser les valeurs par défaut à différents endroits :

  • Avant le lancement d'acidfarm (par ordre d'appel) - les helpers ne sont pas utilisables
    • sys/server.php : Fichier non synchronisé - Reçoit les particularités liées au serveur
      $acid['url']['folder'] = '/site-manager/';
    • sys/config.php : Fichier synchronisé - Reçoit les particularités liées au site
      $acid['def_theme'] = 'default';
      $acid['theme'] = empty($acid['server_theme']) ? $acid['def_theme'] : $acid['server_theme'];
  • Après le lancement d'acidfarm
    • sys/dynamic.php : Fichier synchronisé - Reçoit également les particularités liées au site mais une fois acidfarm lancé. Cela permet par exemple, d'utiliser des conditions propres à l'utilisateur.
      $acid['user']['page'] = Acid::get('url:folder_lang') . AcidRouter::getKey('account');
      $acid['url']['system'] = Acid::get('url:prefix').Acid::get('url:folder');

Inclusions

AcidFarm dispose d'un autocaller. S'il ne connait pas une classe il fera appele au fichier désigné par le tableau de configuration $acid['includes'].

Par convention, nous alimenterons ce tableau dans le fichier sys/includes.php :

// User
$acid['includes']['User']                = 'sys/modules/user.php';
$acid['includes']['UserGroup']           = 'sys/modules/user_group.php';
$acid['includes']['UserGroupAssoc']      = 'sys/modules/user_group_assoc.php';
$acid['includes']['UserPermission']      = 'sys/modules/user_permission.php';

//Site
$acid['includes']['Page']                = 'sys/modules/page.php';
$acid['includes']['Actu']                = 'sys/modules/actu.php';
$acid['includes']['PhotoHome']           = 'sys/modules/photo_home.php';
$acid['includes']['Photo']               = 'sys/modules/photo.php';
$acid['includes']['Seo']                 = 'sys/modules/seo.php';
$acid['includes']['Site']               = 'sys/modules/site.php';

//Tools
$acid['includes']['Contact']                 = 'sys/tools/contact.php';
$acid['includes']['AcidRegistration']        = 'registration/private/lib.php';

// Libraries
$acid['includes']['Lib']          = 'sys/tools/lib.php';
$acid['includes']['Lang']         = 'sys/tools/lang.php';
$acid['includes']['Conf']         = 'sys/tools/conf.php';
$acid['includes']['Ajax']         = 'sys/tools/ajax.php';
$acid['includes']['Rest']         = 'sys/tools/rest.php';
$acid['includes']['Route']        = 'sys/tools/route.php';

// Admin Config
$acid['includes']['SiteConfig']   = 'sys/modules/config.php';

// Conroller Tools
$acid['includes']['SitemapController']        = 'sys/controller/acid/SitemapController.php';

// Print
$acid['includes']['MyTemplate']   = 'sys/template.php';

Routes

index.php

//L'url correspond à http://monurl/produits/*/*
//@products : {$lang['router']['products']['fr'] = 'produits'}
//Affichage d'une fiche produit - appel de la methode products() du controller ProductsController 
AcidRouter::addRoute('products', new AcidRoute('@products/:id_products/:normalize',array('controller'=>'ProductsController','action'=>'products')));

//L'url commence par http://monurl/actualites
//@news : {$lang['router']['news']['fr'] = 'actualites'}
// Page Actu avec X Params Facultatif - appel de la methode index() du controller ActuController 
AcidRouter::addRoute('news', new AcidRoute('@news',array('controller'=>'ActuController'),1));

//L'url commence par http://monurl/* 
//Par défault : affichage d'une page - appel de la methode index() du controller PageController 
AcidRouter::addRoute('page',new AcidRoute(':page_key',array('controller'=>'PageController'),1));

//L'url ne correspond à rien de mentionner plus haut (ici  http://monurl/)
//Si pas de page définie, affichage de la home  - appel de la methode home() du controller PageController 
AcidRouter::addDefaultRoute('index',new AcidRoute('default',array('controller'=>'PageController','action'=>'home')));

sitemadmin.php

L'Administration d'acidfarm n'utilise pas le principe des routes utilisé dans l'index.php.

Cependant, un système d'accès et de controller est en place.

Des méthodes utiles permettent d'interagir sur le menu et les droits d'accès en quelques lignes :

    //Création d'une catégorie du menu "Site web" - niveau utilisateur doit être $def_level
    AdminController::addMenuCat('web',Acid::trad('admin_menu_web'),array('unclickable'=>true,'color'=>$color[3]),$def_level);

    //Adminitration des Photos de l'accueil accessible depuis le menu "Site web"   - niveau utilisateur doit être $def_level
    AdminController::addMenu('photo_home','web','Mes photos',$def_level);
    AdminController::addAccess('photo_home',$def_level,'PhotoHome');

    //Adminitration des utilisateurs accessible depuis le menu  "Site web" - niveau utilisateur doit être $dev_level
    AdminController::addMenu('user','web','Mes utilisateurs',$dev_level);
    AdminController::addAccess('user',$dev_level,'User');

Le Controlleur utilisé est sys/controller/admin/AdminController.php

Controllers

Soit la route suivante :

AcidRouter::addRoute(
    //nom de la route
    'exemple', 
    new AcidRoute(
        //pattern de la route
        '@exemple',
        array(
             //nom la classe controller (et du fichier php)
            'controller'=>'MonExempleController',
            //méthode de la classe à afficher (def : index)
            'action'=>'mamethode', 
            //nom du sous-dossier de sys/controller reccueillant le fichier ( def: 'acid' )
            'module'=>'exemple' 
        )
    )
);

Le Controller désigné se situent dans le dossier sys/controller/exemple/MonExempleController.php

La méthode mamethode de la classe MonExempleController sera appelé.

<?php

class MonExempleController{

    public function index(){
        //Affichage d'un texte par défaut
         Conf::addToContent('Voici mon exemple par défaut');   
    }

    public function mamethode(){

        //affichage du contenu de ma page dont l'identifiant est exemple
        $my_page = new Page();
        $my_page->init('exemple');

        if (!$my_page->getId()) {

            //on affiche une 404
            AcidUrl::error404();

            //ou on redirrige vers la home
             AcidUrl::redirection(Acid::get('url:system_lang');
            return false;

        }

        //gestion des métas
        Conf::addToAriane($my_page->trad('title'),$my_page->url());
        Conf::setMetaDesc('ma meta desc exemple');
        Conf::setPageTitle($my_page->hscTrad('title'));    
        Conf::addToMetaKeys(array('exemple','mon exemple','controller'));

        //affichage de ma page                          
        Conf::addToContent($my_page->trad('content');

    }

}

Themes

Acid::set('def_theme','default');
Acid::set('theme','bootstrap');

Dossier theme/

Le dossier theme/ recueillera les thèmes disponibles.

  • Vous pouvez utiliser un thème unique (auquel cas $acid['def_theme'] sera similaire à $acid['theme']).
  • Vous pouvez aussi utiliser un thème qui s'inspirera d'un autre thème.

Tpl

<?php

//Instanciation d'un objet page
$page = new Page();
$page->init('home-list');

//On reçoit le contenu de /theme/{montheme}/tpl/pages/list.tpl dans $my_content
$my_content = Acid::tpl('pages/list.tpl',array('elts'=>array(1,2,3),'complement'=>'mon complément'),$page);

Dans /theme/montheme/tpl/pages/list.tpl :

<!--
    $v correspond au tableau qui a été soumis à Acid::tpl  
    $o correspond à l'objet $page  qui a été soumis à Acid::tpl  
    $g est un alias de la variable $_GLOBALS
-->

<h1>
    <a href="<?php echo $o->url(); ?>">
        <?php echo $o->hsc('title'); ?>
    </a>
</h1>

<div> <?php echo $o->get('content'); ?> </div>

<?php   
    //on récupère nos éléments dans le tableau $v
    foreach ($v['elts'] as $number) { 
?>
     <div>my number is <?php echo $number; ?></div>   
<?php   
    } 
?>

<?php if ($complement = Lib::getIn('complement',$v)) { ?>
    <div> <?php echo $complement; ?> </div>
<?php } ?>

<footer>
<?php 
    //on peut inclure des tpl dans d'autres tpl
    echo Acid::tpl('pages/list-footer.tpl',$v,$o); 
?>
</footer>

Template.php & outPath

Le fichier /sys/template.php contient la class MyTemplate extension de AcidTemplate qui gère l'affichage de votre site.

On y intègre les propriétés d'affichages communes à tous les thèmes (intégrer les outils de stats au footer, définir les différents type d'affichages, etc.).

Cette classe contient entre autre les différentes méthodes d'affichages (print_default, print_html, print_xml, print_empty, etc.) :

  • En utilisant la configuration : Acid::set('out','default');, le site fera appel à $template->print_default()

  • En utilisant la configuration : Acid::set('out','siteadmin');, le site fera appel à $template->print_siteadmin()

  • En utilisant la configuration : Acid::set('out','xxx');, le site fera appel à $template->print_xxx()

  • En cas d'absence de cette méthode, le site fera appel à $template->print_default()

La méthode Acid::outPath() fera référence au fichier \theme\montheme\out\xxx.php

Ou à défault : \theme\montheme\out\default.php

Ce fichier permet de définir la structure générale d'un thème tout en ayant la main sur l'intégralité du site :

  • intrérogation de la bdd
  • alimentation de la balise header ($this->addJS, $this->addInHead)
  • paramêtrage de la balise body ($this->setBodyAttrs(array('class'=>'maclasse')))
  • etc.

Sass


Activer et Configurer SASS :

$acid['sass']['used'] =  true;

$acid['sass']['enable'] = $acid['sass']['used'];

On active l'utilisation du sass

$acid['sass']['path']['compiled'] = 'compiled/';

Nous configurons le site pour que les fichiers compilés arrivent dans /theme/montheme/css/compiled/

$acid['sass']['mode'] = 'dev'; 

Nous compilerons à la la volée le fichier /theme/montheme/css/sass/monfichiersassnoncompile.scss (en environnement dev uniquement)

$acid['sass']['mode'] = 'prod'; 

Nous intérrogerons /theme/montheme/css/compiled/fichiercsscompile.css


Pour compiler les fichiers SASS, aller dans sys/script/ puis :

php sass_compiler.php -c


Faire appel une ressource sass :

$this->sassUrl('style')

Cette méthode retourne :

/theme/montheme/css/sass/style.scss (en mode dev)

ou /theme/montheme/css/compiled/style.css (en mode prod)

Mode glue ou fullstack

Acidfarm est un CMF, il peut être utilisé en tant que site CMS (fullstack) mais aussi en tant que framework de developpement.

Aussi, il est parfois possible de l'utiliser uniquement pour ses librairies et modules sans gestion de la vue: c'est le mode glue.

  • Dans le fichier index.php, nous appelons le CMS :
    require 'sys/start.php';
  • Lorsque nous exécutons nos scripts en PHP-CLI ou utilisons le mode REST, nous faisons appel au mode glue :
    require 'sys/glue.php';

Modules

Dans Acidfarm, chaque AcidModule est à l'image d'une table en base de données. Une ligne dans cette table, correspond à une instance.

Chaque module héritant de cette classe disposeront alors d'une interface d'Administration pré-générée au moyen des méthodes $monmodule->printAdminInterface() et $monmodule->exePost()

Notez bien qu'un AcidModule est prévu pour l'override. C'est à dire qu'il est souvent nécéssaire de redéfinir certaines méthodes pour personnaliser vos modules. C'est un procédé tout à fait normal, AcidModule utilise de nombreuses méthodes (en plus de ses configurations préconçues) qui vous permettront de cibler au mieux les parties à altérer.

Pour modifier le comportement de tous vos modules à la fois, vous pouvez modifier le fichier sys/modules/core.php

Créer un module

Dans sys/modules/ créer un fichier monmodule.php

class MonModule extends AcidModule {

    //Nom de la table delestée de son prefix ( Acid::get('tbl:prefix') )
    const TBL_NAME = 'mon_module';

    //Nom de la clé primaire 
    const TBL_PRIMARY = 'id_mon_module';

    //Constructeur
    public function __construct($init_id=null) {

        //La table dispose d'un champs id_mon_module qui est un entier 
        $this->vars['id_mon_module'] = new AcidVarInt('Mon ID',true); 
        //Label : Mon Id, entier positif

        //La table dispose d'un champs nom recevant une chaine de caractères
        $this->vars['nom'] = new AcidVarString('Nom'); 
        //Label : Nom

        //La table dispose d'un champs active recevant les valeurs 0 ou 1
        $this->vars['active'] = new AcidVarBool('Actif ?',true); 
        //Label : Actif ?, par défaut sa valeur est 1

        //La table dispose d'un champs timestamp
        $this->vars['madate'] = new AcidVarDateTime('Date');
        //Label : Date

        //La table dispose d'un champs src recevant le chemin vers une image
        //L'interface d'admin Acidfarm permet l'upload et la redimension de l'image
        //--les images seront stockées dans files/monmodule/ 
        $path = Acid::get('path:files').'monmodule/';
        //--on conserve l'image d'origine + 2 formats (large et mini)
        $photo_format = array(
            //le format d'origine n'est pas altéré
            'src'=>array('size' => array(0,0,false),'suffix' => '','effect' => array()),
            //le format large fera 500px de hauteur et de largeur maximum, et portera le suffix _l
            'large'=>array('size' => array(500,500,false),'suffix' =>'_l', 'effect' => array()),
            //le format mini fera 48px par 48px (crop au centre), et portera le suffix _s
            'mini'=>array('size' => array(48,48,true),'suffix' => '_s','effect' => array())
        );
        //--le format de previsualisation dans l'admin sera mini
        $config = array('format'=>$photo_format,'admin_format'=>'mini');
        $this->vars['src']  =   new AcidVarImage( 'Mon image', $path, $config);
        //Label : Mon image, chemin de destination $path, configuration $config

        //Seul un administrateur peut ajouter/modifier/supprimer des éléments de ce module
        //--Décommenter cette ligne pour donner ces droits à un utilisateur enregistré
        //$this->config['acl']['default'] =  Acid::get('lvl:member');

        //Un module peut être personnalisé en jouant sur la valeur de $this->config
        $this->config['admin']['add']['def'] = array('adate'=>date('Y-m-d H:i:s'));
        //Dans le formulaire d'ajout, la date sera initialisée à la date du jour

        parent::__construct($init_id);

    }
}

Dans sys/includes.php, ajouter :

$acid['includes']['MonModule']   = 'sys/modules/monmodule.php';

Dans siteadmin.php, avant l'appel de AcidRouter::run();, ajouter :

AdminController::addMenu(MonModule::TBL_NAME,'web','Gérer mon module',$def_level);
AdminController::addAccess(MonModule::TBL_NAME,$def_level,'MonModule');

Instancier un module

Par id :


//Récupération de l'élément d'id 1 depuis la base de données
$mon_module = new MonModule(1); 

//Si l'instanciation a réussi
if ($mon_module->getId()) {
    //La ligne correspondante existe en bdd 
    echo $mon_module->get('nom');
}

Par un tableau de valeurs:


//Seuls les champs representant le module seront utilisés
$configuration = array(
    'id_mon_module'=>1,
    'nom'=>'Mon nom', 
    'active'=>true, 
    'madate'=>'2010-05-03 15:20:00',
    'champs_divers'=>'Pas pris en compte'
);

$mon_module = new MonModule($configuration); 

//Cette appel affichera 1
echo $mon_module->getId();

Lister les élements en base de données

Récupérer tous les éléments

 if ($res = MonModule::dbList()) {
    foreach ($res as $elt) {
        $mod = new MonModule($elt);
        echo $mod->get('nom');
    }
 }

Récupérer les éléments au moyen de filtres


 //Seulement les lignes :
 $filtre = array(
    array('active','=',1), //dont le champs active vaut 1
    //ET 
    array('nom','LIKE','%bon%') //dont le nom content "bon"
 );

 //Ordonné par date décroissante et nom croissant
 $ordre = array('madate'=>'DESC','nom'=>'ASC'); 

 //Seulement les 10 premiers éléments
 $limite = 10;  //ou '0, 10'

 if ($res = MonModule::dbList($filtre,$ordre,$limite)) {
    foreach ($res as $elt) {
        $mod = new MonModule($elt);
        echo $mod->get('nom');
    }
 }

Jointures

 //dont le champs active de la table User vaut 1
 $filtre = array( array(User::dbPref('active'),'=',1) );

//Jointure avec la table UserGroupAssoc sur le champs id_user
 $jointure = array('UserGroupAssoc'=>array('id_user')))

 if ($res = User::dbListMods($jointure,$filtre) {
    foreach ($res as $elt) {
        $user = new User($elt);
        $assoc = new UserGroupAssoc($elt);
    }
 }

Altéreration d'objet et base de données

Mise à jour d'un objet :

//Récupération de l'élément d'id 1
$mod = new MonModule(1);

$changes = $mod->intiVars(array('active'=>false));

//$changes est un tableau recueillant le nom des champs qui ont réellement été modifiés
if ($changes) {
    var_dump($changes); 
    //Array([0]=>'active')
}

Ajout en bdd :

    $mod = new MonModule();
    $mod->initVars(array('nom'=>'mon ajout'));

    if ($mod->dbAdd()) {
        echo $mod->getId(); //l'id de l'objet a été mis à jour
    }

Modification en bdd :

    $mod = new MonModule(3);
    $changes = $mod->initVars(array('nom'=>'ma modif'));

    //On ne met à jour que les champs altérés 
    $mod->dbUpdate($changes);  

    //On peut aussi mettre à jour tous les champs 
    $mod->dbUpdate('all');

Ajout ou Modification ?

    $changes = $mod->initVars(array('nom'=>'mon alteration'));

    //Ajoute ou met à jour si l'id est différent de 0
    $mod->dbSave($changes);  

Mises à jours

Le Principe

Pour aider les développeurs dans la maintenance de leurs sites (en cas de versionning par exemple), le framework est configuré pour éxecuter les mises à jour automatique situées dans le dossier sys/update/

Dans ce dossier, on peut trouver :

  • Les dossiers de mises à jour : ils seront parcourus par ordre alphabétique.

    Par convention nous les nommerons avec la date du jour suivi d'un index numérique.

    Exemple : 2016-02-01-1

  • Le curseur last_version.txt : il recueille le nom du dossier qui dispose de la dernière mise à jour à exécuter - versionné

  • Le curseur cur_version.txt : il recueille le nom du dossier contenant les dernières mises à jour effectuées sur le site - non versionné

Lorsque le curseur cur_version.txt est inférieur au curseur last_version.txt, Acidfarm lance la procédure de mise à jour, puis change la valeur du fichier cur_version.txt

Lorsqu'il traite un dossier de mise à jour, Acidfarm parcourt (dans l'ordre alphabétique) chaque fichier présent dans le dossier, puis l'éxécute (si son extension est valide).

Les fichiers executables sont les suivants :

  • Les fichiers .sql : les occurences de acid_ seront remplacées par le prefix bdd de la configuration acidfarm

  • Les fichiers .php : lors de l'exécution, acidfarm est chargé

Les dossiers .content et .system sont des sous-dossiers de mises à jour (fonctionant exactement de la même manière), mais prévus à des fins particulières.

Vous pourrez trouver de nombreux exemples de mises à jour dans le fichier sys/update/sample.txt.

Exemple

Mon dossier sys/update est le suivant

sys/update
    - 2015-01-01
        - 01.sql 
            UPDATE acid_user SET email = 'BAD_EMAIL'
    - 2015-03-01
        - 01.sql
            UPDATE acid_user SET email = '' WHERE email='BAD_EMAIL'
        - 02.php
            <?php 
            //on liste les utilisateurs
             if ($res = User::dbList()) {
                //on les parcourt
                foreach ($res as $elt) {
                    //on instancie
                    $u = new User($elt);
                    if (!$u->get('email')) {
                        //on génère un email
                        $email = $user->get('nom').'.'.$user->get('prenom').'@test.tdl';
                        //on utilise on fonction (ici, fictive) qui certifie son existance
                        if (monEmailExiste($email)) {
                            //on met à jour l'utilisateur
                            $changes = $u->initVars(array('email'=>$email)); 
                            $u->dbUpdate($changes);
                        }
                    }
                }
             }
    - cur_version.txt
            2015-01-01
    - last_version.txt
            2015-03-01

Lors du prochain appel d'acidfarm :

  • le fichier sys/update/2015-03-01/01.sql puis sys/update/2015-03-01/02.php seront éxécutés.
  • le fichier sys/cur_version.txt aura le contenu suivant 2015-03-01

Formulaires/Post traitement

Les bases

Via le fichier sys/post.php, acidfarm a fait en sorte de vous permettre d'interagir avec chaque AcidModule depuis un formulaire POST.

Les pré-requis sont les suivants :

  • un champs module_do doit avoir pour valeur la classe à Instancier
  • un champs ${nom_de_ma_table}_do doit avoir pour valeur l'action à effectuer (par exemple, add, update, del)
  • vous pouvez désigner l'id de l'élément à altérer en ajoutant un champs correspondant à la clé primaire de l'objet
  • vous devez avoir les droits requis (par défaut, être connecté en tant qu'admin)

Pour modifier l'identité de l'utilisateur 1, on aura par exemple :

<form  method="POST">
<div>
    <input type="hidden" name="module_do" value="User" />
    <input type="hidden" name="user_do" value="update" />
    <input type="hidden" name="id_user" value="1" />

    Nom  : <input type="text" name="firstname" value="Nom actuel" />
    Prénom : <input type="text" name="lastname" value="Prénom actuel" />

    <input type="submit" value="Valider" /> 
</div>
</form>

Pour une création :

<form  method="POST">
<div>
    <input type="hidden" name="module_do" value="User" />
    <input type="hidden" name="user_do" value="add" />
    <input type="hidden" name="active" value="0" />

    Nom  : <input type="text" name="firstname" value="Nom actuel" />
    Prénom : <input type="text" name="lastname" value="Prénom actuel" />

    <input type="submit" value="Valider" /> 
</div>
</form>

Pour une suppression :

<form  method="POST">
<div>
    <input type="hidden" name="module_do" value="User" />
    <input type="hidden" name="user_do" value="del" />
    <input type="hidden" name="id_user" value="1" />
    <input type="submit" value="Supprimer membre 1" /> 
</div>
</form>

L'ajout d'un champs next_page vous permettra de choisir l'url de redirection en cas de succès.

Post traitements

Si les pré-requis du formulaire sont vérifiés, Acidfarm fait appel à la méthode exePost() du module ciblé.

Vous pouvez overrider les méthodes suivantes pour personnaliser leurs postTraitements

exePost

Pour ajouter un post traitement, modifier la méthode exePost de votre classe :

public function exePost() {

    if ($this->getPostDo()=='custom') {
        $object = self::build($_POST['id_mon_module']);
        //post traitement        
        return $object;
    }

    return parent::exePost();
}

postAdd

La méthode postAdd($vals,$dialog=null) gère le postProcess d'ajout. Elle retourne l'objet créé pour valeur (false en cas d'erreur).

Cette méthode répond au formulaire généré par la méthode printAdminAddForm().

postUpdate

La méthode postUpdate($vals,$dialog=null) gère le postProcess de mise àjour . Elle retourne l'objet modifié pour valeur (false en cas d'erreur).

Cette méthode répond au formulaire généré par la méthode printAdminUpdateForm().

postRemove

La méthode postRemove($id=null,$dialog=null) gère le postProcess de suppression. Elle retourne l'objet supprimé pour valeur (false en cas d'erreur).

postSuccess

Vous pouvez modifier la méthode postSuccess($vals=array(),$do=null) pour ajouter des traitemetns supplémentaire en cas de succès :

public function postSuccess($vals=array(),$do=null) {

        //cache time
        if (in_array($do, array('add','update'))) {
            $this->updateCacheTime();
        }

        return true;
}

Champs obligatoires

Vous pouvez rendre certains champs des formulaires d'administration obligatoire en modifiant la méthode getControlledKeys($do)

protected function getControlledKeys($do) {
    switch ($do) {
        case 'add'
            return array('nom');
        break;
        default :
            return  array();
        break;
    }
}

Pour un contrôle avancé des formulaires d'administration, vous pouvez vous référer à la méthode checkVals($tab,$do)

Schéma

Le postProcess depuis sys/post.php :

AcidModule->exePostProcess {

    //check le postTraitement
    exePost {

        //transforme $_POST en fonction des droits
        postACL{}

        //contrôle la conformité des valeurs récupérées (+ mise en session temporaire des entrées)
        checkVals{

            //définit les clés à contrôler
            getControlledKeys{}
        }

        //en fonction de getPostDo(), execute l'une des méthodes suivantes
        postAdd, postUpdate, postRemove {

            //Permet la configuration de l'objet avant le traitement
            postConfigure{}

            //En cas de succès, permet appliquer de traitements supplémentaires
            postSuccess{}
        }

    }

    //retourne un JSON si $_POST['ajax'] (par défaut) est défini 
    treatAjax {}

}

Outils pratiques

Base de données

AcidDB est un singleton de PDO, libre à vous de l'utiliser pour effectuer vos requêtes de la plus simple à la plus complexe.

$sql = "SELECT `id_user` FROM ".User::tbl()." WHERE `active` = 1";
if ($res  = AcidDB::query($sql)->fetchAll(PDO::FETCH_ASSOC)) {
    foreach ($res as $elt) {
        echo $elt['id_user'];
    }
}

Sessions

Les sessions d'Acidfarm sont stockées en base de données et sont initialisée à l'aide d'un cookie.

Sessions permanentes

Définir une variable de session

$tableausession = array('cle'=>'valeur');
Acid::sessSet('exemple',$tableausession);

Acid::sessSet('exemple:cle2','valeur2');

Obtenir une valeur en session

Acid::sessGet('exemple:cle'); //affiche 'valeur'
Acid::sessGet('exemple:cle2'); //affiche 'valeur2'

Sessions temporaires

Définir une variable limitée dans le temps

AcidSession::tmpSet('cle','valeur',100); //expiration dans 100 secondes

Obtenir une valeur en session temporaire

AcidSession::tmpGet('cle'); //affiche 'valeur'

Notifications

PHP

Vos post process peuvent utiliser les sessions d'Acidfarm pour dialoguer avec l'utilisateur.

AcidDialog::add('info','<h1>Information</h1><p>Mon message</p>');
AcidDialog::add('banner','Des champs sont manquants');
AcidDialog::add('error','Formulaire invalide');

Javascript

Dans sys/template.php, décommenter le code suivant :

public function getBwin() {
    return Acid::tpl('screens/bwin.tpl');
}

En javascript faire appel à la popin :

<script type="text/javascript">
<!--
    Bwin.call({title:'Mon titre',content:'Mon contenu'});
-->
</script>

Logs

Dans votre code :

Acid::log('TAG','Ici mon log'); //génère une entrée dans le dossier logs/ 

Vous pouvez personnaliser votre environnement pour n'activer que les logs disposant du TAG souhaité. Dans sys/server.php :

//$acid['log']['keys']          = '*';
$acid['log']['keys']            = array('INFO','POSTINFO','HACK','ERROR','MAINTENANCE','FILE'); 
//$acid['log']['type']          = 'daily'; // single / daily
//$acid['log']['colorize']      = array(); // array('HACK'=>'red','DEBUG'=>'yellow')

Emails

De manière générale :

Mailer::send('Sender','sender@domain.tdl','destinataire@domain.tdl',Mon sujet','Mon message');

Au staff :

Mailer::sendStaff('Mon sujet','Mon message'); //un email sera envoyé  à Acid::get('site:email');

A un utilisateur :

$u = new User(1);

//un email sera envoyé  à l'adresse e-mail de l'utilisateur
$u->sendMail('Mon sujet','Mon message');

Divers

Soyez curieux, de nombreuse classes outils sont présentes dans acid/tools/ :

  • AcidBash //Coloration bash
  • AcidBrowser //Parcours de fichiers
  • AcidCookie //Gestion des cookies
  • AcidCSV //Gestion CSV
  • AcidExport //Export de données
  • AcidFacebook //Partage facebook
  • AcidForm //Gestion des formulaires HTML
  • AcidFs //Gestion des fichier
  • AcidGmap //Passerelle Google Map
  • AcidMail //Envoi d'emails
  • AcidMediatheque //Parcours de fichiers avancé
  • AcidPagination //Assistant de pagination
  • AcidPaypal //Passerelle paypal
  • AcidRss //Gestion Rss
  • AcidSiteMap //Gestion de fichier sitemap
  • AcidTable //Gestion de tableaux html
  • AcidTemplate //Outil d'affichage
  • AcidTime //Manipulation des dates et heures
  • AcidTimer //Compteurs de temps
  • AcidTwitter //Partage twitter
  • AcidUrl //Manipulation des url et redirections
  • AcidZip //Gestion de fichiers Zip

Configurations diverses

Environnement

Configuration locale

Après l'iinstallation, dans sys/server.php

<?php 

//modifier le domaine associé au site
$acid['url']['scheme']          = 'http://';
$acid['url']['domain']          = 'mondomaine';
$acid['url']['folder']          = '/';

//modifier les paramètres de connection à base de données
$acid['db']['type']             = 'mysql';
$acid['db']['host']             = 'localhost';
$acid['db']['port']             = '3306';
$acid['db']['user']             = 'dbuser';
$acid['db']['pass']             = 'dbpass';
$acid['db']['base']             = 'database';
$acid['db']['prefix']           = 'acid_';

//Activer Sass
$acid['sass']['enable'] = true;
$acid['sass']['mode'] = 'dev'; //génération à la volée
//$acid['sass']['mode'] = 'prod'; //utilisation des ressources compilées

Front

Configuration générale

Dans sys/config.php

<?php 

//Activation du mode multilangue 
$def_lang = 'fr'; 
$acid['lang']['use_nav_0']      = true;
$acid['lang']['default']        = $def_lang;
$acid['lang']['available']      = array($def_lang,'en','es');

//Désactiver la protection javascript du formulaire de contact
$acidconf['contact']['shield'] = false;

//Définir les méta par défaut
$acidconf['meta']['keywords']['fr']['default']      = array('exemple', 'de', 'mots-clé');
$acidconf['meta']['description']['fr']['default']       = "exemple de metadesc";
$acidconf['meta']['image']['fr']['default']     = "/ascreen.jpg";

Admin

Les modules

Override

Vous pouvez overrider la méthode postConfigure, pour personnaliser l'interface d'administration :

class MonModule extends AcidModule {

   ...

    public function printAdminConfigure($do='default',$conf=array()) {

        /* LE LISTING */

            //Enumérer les champs à afficher dans le listing (tous si non défini)
            $this->config['admin']['list']['keys'] = array('champ1','champ2','champ3','active'); 
            //A contrario, définir les champs à ne pas afficher dans le listing
            $this->config['admin']['list']['keys_excluded'] = array('champs4');

            //Définir l'ordre par défaut
            $this->config['admin']['list']['order'] = array('champ3'=>'DESC');

            //Définir la pagination par défaut
            $this->config['admin']['list']['limit'] = 100;

            //Lier le listing à une jointure (Module User sur le champ commun id_user)
            $this->config['admin']['list']['mods'] = array('User'=>array('id_user')); 

            //Modifier les entêtes
            $this->config['admin']['head']['champ1'] = 'Le fameux champs 1'; 

            //Remplacer la valeur du champs par un formulaire d'édition
            $this->config['print']['champ1']= array('type'=>'quickchange','ajax'=>false));

            //Remplacer la valeur du champs par un bouton switch
            $this->config['print']['active']= array('type'=>'toggle','ajax'=>true);

            //Remplacer la valeur du champs par une adresse email avec mailto
            $this->config['print']['email'] = array('type'=>'mailto');

            //Remplacer la valeur du champs par le retour d'une fonction
            $this->config['print']['champ2'] = array(
                'type'=>'func',
                'name'=>'MonModule::printChamp2',
                'args'=>array('__ELT__','__VAL__',$autre_argument)
            );

            //Ajouter des filtres en entêtes 
            $this->config['admin']['list']['head_filters'] = array('active'=>$this->vars['active']->getElts());

            //Pour plus d'exemple se référer à la méthode $this->getPrinted($key)

        /* FORMULAIRE */

             //Enumérer les champs à intégrer au formulaire d'ajout / édition
            $this->config['admin']['add']['keys'] =
            $this->config['admin']['update']['keys'] = array('champ1','champ2','champ3');
            $this->config['admin'][$do]['keys_excluded'] = array('champ4');

            //Redirection en cas de succès 
            $this->config['admin'][$do]['next_page'] = $url;

            //Définir les clés multilingues
            $this->config['multilingual']['keys'] = array('champ2', 'champ3');

            //Définir des attributs html au champ
            $this->config['admin'][$do]['params']['champ1'] = array(
                'id'=>'monidchamp1',
                'class'=>'champavecclass'
            );

            //Définir du texte avant ou après le champ
            $this->config['admin'][$do]['start']['champ1'] = 'texte avant : ';
            $this->config['admin'][$do]['stop']['champ1'] = '<a href="lien">lien de fin</a>';

            //Transformer le formulaire d'un AcidVarInt en select
            $this->vars['champs3']->setElts(array(0=>'Rien','1'=>'Un peu', 2=>'Beaucoup'));
            $this->vars['champs3']->setForm('select'); 

            //Transformer le formulaire par du texte libre
            $this->vars['champs2']->setForm('free',array(
                'free_value'=>'ici mon <a href="lien">lien</a>'
            )); 

            //pour plus d'exemple de transformation de formulaire se référer à AcidVar::setForm

        /* Appel du parent */
            return parent::printAdminConfigure($do,$conf);
    }

}

Schéma

AcidModule->printAdminInterface{

    //Vérifie l'accès de l'utilisateur
    getUserAccess{}

    //controller par défaut en fonction de $this->admin_nav['do'] (par défaut $_GET[$this->preKEy('do')])
    exeAdminController{

        //Affichage détaillé d'un élément
        printAdminElt {

            //configuration de l'objet avant affichage du formulaire
            printAdminConfigure {}

        }

        //Formulaire de recherche menant à un listing
        printAdminSearch {

            //configuration de l'objet avant affichage du formulaire
            printAdminConfigure {}

        }

        //formulaires d'ajout/mise à jour 
        printAdminAdd, printAdminUpdate {

            //Affichage du ajout/mise à jour après préconfiguration ($this->config['admin']['add']['def'])
            printAdminAddForm, printAdminUpdateForm {

                //méthode générique d'affichage du formulaire d'ajout/mise à jour
                printAdminForm {

                    //configuration de l'objet avant affichage du formulaire
                    printAdminConfigure {}

                    //récupération auto des clés multilngues ($this->config['multilingual']['keys'] sinon)
                    getMultiLingualKeys{}

                    //personnalisation du formulaire avant le traitement automatique des champs
                    printAdminFormStart {}

                    //personnalisation du formulaire après le traitement automatique des champs
                    printAdminFormStop {

                        //ajout du bouton submit du formulaire (ex : mode submit/image)
                        printAdminFormSubmit {}
                    }

                    //génère l'ergonomie multilingue si nécéssaire
                    printAdminFlags {}

                }

            }

        }

        //Liste des éléments
        printAdminList{

            //configuration de l'objet avant affichage du formulaire
            printAdminConfigure {}

            //récupèration des filtres $_GET
            getAdminListOptions{}

            /récupération du nombre d'éléments
            dbListMods, dbCount{}

            //récupếration des informations nécéssaires pour paginations et entêtes/footline
            getAdminListParams()

            //génération de l'entête/footline d'informations 
            printAdminListInfo

            //récupération des éléments
            dbList, dbListMods, dbCount{}

            //génération des filtres personnalisés en entête ($this->config['admin']['list']['head_filters'])
            genAdminListHeadFilter{}

            //génération du tableau de listing
            genAdminListContent {

                //format les éléments reçu avant la génération 
                genAdminListFormat{}

                //génère l'entete du tableau
                genAdminListHead{}

                //génration d'une ligen du tableau
                genAdminListLineCustomClass{}
                genAdminListLine{}

                //génération du tableau
                printAdminTab{}

            }

            //regroupement des éléments générés dans une structure HTML
            printAdminListBody{}

        }

    }

    //controller personnalisé $config['controller']
    callFunction{}

}

Général

Dans siteadmin.php, décommenter $acid['server_theme'] = 'bootstrap'; pour activer le mode bootstrap

Les exemples ci-dessus ne sont pas exaustifs, soyez curieux !

Scripts

Scripts utiles

Par défaut, Acidfarm dispose de quelques scripts utiles dont vous pouvez vous inspirer : ceux-ci sont présents dans le dossier sys/script/.

Pour des raisons de sécurité, ceux-ci sont prévus pour être appelés en ligne de commande uniquement.

Assister la création de vos modules à l'image de votre base de données

~sys/script - php class_from_table -t=all -p=acid_ 

Cette commande generera des fichiers modules dans le dossier sys/script/class/ pour chaque tables presente dans votre base de données. A l'aide des fichiers _includer.txt et _lang.txt, vous n'aurez qu'à deposer les modules qui vous intéressent dans le dossier sys/modules/, puis mettre à jour le fichier sys/includes.php afin de les activer.

Dupliquer vos tables Acidfarm vers un autre prefix

~sys/script - php db_create_branch.php -b=v2 -c

Les tables disposant du prefix acidfarm seront dupliquées avec un nouveau prefixe, ici : V2_acid_*nomtable*

Tester la bonne configuration de l'envoi d'e-mail

~sys/script - php test_email.php -e=monemail@domain.tdl -c

Vous recevrez deux e-mails à l'adresse renseignée si votre site et/ou serveur sont bien configurés

Complitation des fichiers SASS

~sys/script - php sass_compiler.php -c

Compile tous les fichiers scss dans vos dossiers theme/*/css/sass/

Regénération des miniatures

~sys/script - php regen_photos.php -c

Les images associées aux module Photo, seront regenérées à partir de leur format src.

Soyez curieux

Il en existe d'autres...

Cron

Par convention, nous plaçons les scripts cron dans le dossier sys/cron/, Acidfarm n'a pas besoin de cron pour fonctionner correctement.

API REST

Acidfarm dispose d'outils permettant la mise en place d'une API REST (et authentification digest) depuis le dossier rest/.

Les routes sont créés dans rest/index.php :

//Getters
AcidRouter::addGet('list',new AcidRoute(':module/list',array('controller'=>'RestController','action'=>'getList','module'=>'rest')));
AcidRouter::addGet('get',new AcidRoute(':module/get/:id_module',array('controller'=>'RestController','action'=>'get','module'=>'rest')));

//POST
AcidRouter::addPost('post',new AcidRoute(':module',array('controller'=>'RestController','action'=>'post','module'=>'rest')));

//PUT
AcidRouter::addPut('put',new AcidRoute(':module',array('controller'=>'RestController','action'=>'put','module'=>'rest')));

//DELETE
AcidRouter::addDelete('delete',new AcidRoute(':module',array('controller'=>'RestController','action'=>'delete','module'=>'rest')));

//Si pas de page définie, affichage de la home
AcidRouter::addDefaultRoute('404',new AcidRoute('default',array('controller'=>'RestController','action'=>'call404','module'=>'rest')));

Le controller se situe dans le fichier sys/controller/rest/RestController.php :

class RestController{

    public function getList(){
        $module = AcidRouter::getParam('module');
        if (Acid::get('includes:'.$module)) {
            $m = new $module();
            if ($res = $m->restList()) {
                Rest::status200($res);
            }else{
                Rest::status204();
            }

        }

        $this->call404();
    }

    public function get(){

        $module = AcidRouter::getParam('module');
        $id = AcidRouter::getParam('id_module');
        if (Acid::get('includes:'.$module)) {
            $m = new $module($id);
            if ($res = $m->restGet()) {
                Rest::status200($res);
            }else{
                Rest::status204();
            }

        }

        $this->call404();
    }

    public function post(){
        Rest::status403();
    }

    public function put(){
            Rest::status403();
    }

    public function delete(){
        Rest::status403();
    }

    public function call404(){
        Rest::status404();
    }

}

Par défaut, Acidfarm est configuré pour permettre l'accès get/list aux modules disposant de la configuration $this->config['rest']['active'], auquel cas l'api fera appel aux méthodes $monmodule->restGet() et $monmodule->restList().

Test

PHPunit

Le fichier de configuration phpunit.xml et l'executable se trouvent à la racine du site

Par défaut les jeux de tests se situent dans le dossier sys/tests/

Pour lancer les tests, lancer la commande suivante depuis la racine : php phpunit.phar

Codeception

Le fichier de configuration codeception.yml et l'executable se trouvent à la racine du site

Par défaut les jeux de tests se situent dans le dossier sys/tests/codeception/

Pour lancer les tests, lancer la commande suivante depuis la racine : php codecept.phar run

API Documentation

Vous retrouverez l'API Documentation à cette adresse : http://doc.acidfarm.net/

Actuellement basée sur la branche master, elle n'est pas à jour (car nous utilisons temporairement la branche multilangue).