Model

Représente Les classes persistantes du système. Par exemple Une classe Livre. Nous allons utiliser un système de gestion des bibliothèques pour expliquer cette partie.
Dans votre application, créez un dossier “model” qui contiendra vos classes. Pour chaque classe, vous devez créer sa définition.

1. Notion de "Model Définition"

a. Exemple de code

<?php
namespace myapp\model;
use muuska\constants\DataType;
use muuska\constants\FieldNature;
use muuska\model\AbstractModelDefinition;
use myapp\option\AccessibilityProvider;
class LibraryDefinition extends AbstractModelDefinition
{
    protected static $instance;
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new static();
        }
        return self::$instance;
    }
    protected function createDefinition()
    {
        return array(
            'name' => 'library',
            'primary' => 'id',
            'autoIncrement' => true,
            'fields' => array(
                'addressId' => array(
                    'type' => DataType::TYPE_INT,
                    'nature' => FieldNature::EXISTING_MODEL_ID,
                    'required' => true,
                    'reference' => AddressDefinition::getInstance()
                ),
                'name' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::NAME, 'maxSize' => 200
                ),
                'openingTime' => array(
                    'type' => DataType::TYPE_STRING,
                    'validateRule' => 'isGenericName'
                ),
                'accessibility' => array(
                    'type' => DataType::TYPE_INT,
                    'nature' => FieldNature::OPTION,
                    'optionProvider' => new AccessibilityProvider()
                ),
                'image' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::IMAGE
                ),
                'description' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::LONG_TEXT
                )
            )
        );
    }
    public function createModel()
    {
        return new Library();
    }
}

 

b. Obtention d’une instance unique

Le bloc de code suivant doit être ajouté dans toutes vos définitions c’est pour s’assurer qu’on ait qu’une seule instance de la classe dans l’application.

 

protected static $instance;
public static function getInstance()
{
    if (self::$instance === null) {
        self::$instance = new static();
    }
    return self::$instance;
}

 

c. La méthode « createModel »

La méthode « createModel » permet de fournir le moyen de créer une nouvelle instance d’un model.

 

d. La méthode «createDefinition»

La méthode «createDefinition» retourne un tableau associatif définissant la classe. Le tableau suivant explique ces différents champs.

- Champs

  • name
    1. Description : Représente le nom de la classe qui sera utilisée par le support de persistance (Par exemple pour la base de données ça représentera le nom de la table).
    2. Type de donnée : Chaine
    3. facultatif : non
  • primary 
    1. Description : Le nom du champ représentant l’identifiant de l’objet.
    2. Type de donnée : Chaine
    3. facultatif : Oui (Si l’objet a plusieurs identifiant)
  • primaries
    1. Description : Nom des champs permettant d’identifier l’objet.
    2. Type de donnée : tableau
    3. facultatif : Oui (Si l’objet a un seul identifiant)
  • autoIncrement 
    1. Description : Indique si l’on veut que la valeur de l’identifiant d’un objet soit attribué automatiquement. Ce champ n’est utile que pour les Classes ayant un seul identifiant.
    2. Type de donnée : booléen
    3. facultatif : oui
  • multilingual
    1. Description Permet de spécifier si l’objet prend en compte le multilingue.
    2. Type de donnée : booléen
    3. facultatif : oui
  • uniques
    1. Description Permet de spécifier un groupe d’attributs pour lesquelles on ne veut pas avoir plusieurs enregistrements avec les mêmes couples de valeurs. Par exemple si je ne veux pas avoir deux auteurs avec le même nom et prénom
      'uniques' => array(
            array('firstName', 'lastName')
       ),
    2. Type de donnée : Tableau associatif
    3. facultatif : oui
  • fields
    1. Description : Représente la définition des attributs persistant de la classe.
    2. Type de donnée : Tableau associatif
    3. facultatif : non
  • presentationFields 
    1. Description Champs utilisés pour la description de l’objet et aussi pour l’auto complétion.
      Si vous ne renseignez pas cette information, le système cherchera les champs appropriés parmi les valeurs suivantes (dans cet order) : « firstName + lastName », « label », « displayName », « name », « title », « code », « reference».firstName + lastName“,“Label”, “displayName”, “name”, “title”, “code”, “reference”.
    2. Type de donnée : tableau
    3. facultatif : oui
  •  presentationFields Separator 
    1. Description Le séparateur à utiliser au cas où "presentationFields" contient plus d’un élément. La valeur pas défaut est l’espace.
    2. Type de donnée : Chaine
    3. facultatif : oui
  • projectType 
    1. Description : Le type de projet auquel l’objet est associé. La valeur par défaut est \muuska\project\constants\ProjectType::Application
    2. Type de donnée : Chaine
    3. facultatif : oui
  • projectName 
    1. Description Le nom du projet auquel l’objet est associé.
    2. Type de donnée : Chaine
    3. facultatif : oui
  • associations 
    1. Description Permet de définir les associations multiples. C’est tableau associatif où la clé représente le nom de l’association et la valeur est un tableau définissant l’association. La définition de l’association est un tableau associatif avec les infos suivantes :
      • reference : objet représentant la définition de la classe externe.
      • field : nom du champ représentant l’identifiant de l’objet courant dans la classe externe
    2. Type de donnée : tableau
    3. facultatif : oui

e. Définition des associations multiples

'associations' => array(
    'books' => array(
        'reference' => BookDefinition::getInstance(),
        'field' => 'libraryId'
    ),
    'speciatilies' => array(
        'reference' => LibrarySpecialityDefinition::getInstance(),
        'field' => 'libraryId'
    ),
    'types' => array(
        'reference' => LibraryTypeDefinition::getInstance(),
        'field' => 'libraryId'
    ),
)

f. Définition d’un champ

Le champ « fields » de la définition du Model retourné par la méthode « createDefinition»

Le champs "fields" est un tableau associatif représentant la définition des attributs persistant de la classe.

NB: Si dans la méthode "createDefinition" le champ "autoIncrement" est définit avec la valeur "true", la propriété représentant l’identifiant de la classe ne doit pas figurer dans le tableau "fields” table.

Le tableau « fields » est de la forme "clé-valeur" où :

  • La "clé" est une chaine de caractère représentant le nom d’une propriété de la classe exemple " firstName "
  • La "value" est un tableau associatif représentant la définition de la propriété. Le tableau suivant liste des champs disponibles :

- Champs

    • type
      1. Description : Le type de donnée manipulé par l’attribut. Ce type est le type sous lequel la donnée sera persistée. (entier, chaine de caractère, booléen, etc…) Un ensemble de constante sont définit dans la classe muuska\constants\DataType.
      2. Type de donnée : entier
      3. Optional : non
    • nature
      1. Description : Représente la nature de la donnée. C’est-à-dire le type d’information que la variable est censé contenir ça peut être un numéro de téléphone, une adresse email, un mot de passe, un nom, etc…
        Un ensemble de constante sont définit dans la classes muuska \constants\FieldNature.
      2. Type de donnée : entier
      3. Optional : oui
    • required
      1. Description : Permet de spécifier si l’attribut est obligatoire ou pas.
      2. Type de donnée : booléen
      3. Optional : oui
    • validationRule 
      1. Description : Permet de spécifier le nom de la méthode qui sera utilisé pour la validation des données de l’attribut. Ce nom doit correspondre à un nom de méthode se trouvant dans la classe muuska\validation\ValidationRuleManager.
        Exemple « isPhoneNumber »
      2. Type de donnée : Chaine
      3. Optional : oui
    • validationRules
      1. Description Liste des règles de validation
      2. Type de donnée : tableau
      3. Optional : oui
    • maxSize
      1. Description : Le nombre de caractère maximum autorisé par l’attribut.
      2. Type de donnée : entier
      3. Optional : oui
    • minSize
      1. Description : Le nombre de caractère minimum autorisé par l’attribut.
      2. Type de donnée : entier
      3. Optional : oui
    • maxValue
      1. Description : Valeur maximum autorisé
      2. Type de donnée : entier
      3. Optional : oui
    • minValue
      1. Description : Valeur minimum autorisé
      2. Type de donnée : entier
      3. Optional : oui
    • unique
      1. Description : Permet de spécifier la valeur de l’attribut doit être unique par exemple je ne veux pas avoir deux livres dans mon système avec le même code.
      2. Type de donnée : booléen
      3. Optional : oui
    • reference
      1. Description : N’est requis qu’au cas où la nature du champ à la valeur FieldNature::EXISTING_MODEL_ID. Il représente l’objet contenant la définition de la classe vers laquelle l’attribut pointe.
        Cet objet doit être une instance de la classe
        “Muuska \ model \ AbstractModelDefinition”.
      2. Type de donnée : Objet
      3. Optional : oui
    • onDelete
      1. Description : N’est requis qu’au cas où la nature du champ à la valeur FieldNature::EXISTING_MODEL_ID. Permet de spécifier le comportement (CASCADE, RESTRICT, etc…) en cas de suppression de la référence de l’objet.
        Un ensemble de constante sont définit dans la classe muuska\dao\constants\ReferenceOption.
      2. Type de donnée : entier
      3. Optional : oui
    • optionProvider
      1. Description : N’est requis qu’au cas où la nature du champ à la valeur FieldNature::OPTION.
        Représente l’objet qui fournira les options à utiliser.
        Cet attribut est utile au cas où l’on a une liste de valeur prédéfinit pour un champ en d’autre terme ça représente les énumérations.
        Cet objet doit être une instance de la classe « muuska\option\ AbstractOptionProvider ».
      2. Type de donnée : Objet
      3. Optional : oui
    • validator
      1. Description : Permet de spécifier un validateur personnalisé pour le champ.
        Cet objet doit implémenter l’interface \muuska\validation\Validator.
        La classe \muuska\validation\DefaultValidator
        Implémente cette interface et vous fournit un moyen de créer une instance en définissant une fonction de rappel.
      2. Type de donnée : Objet
      3. Optional : oui

Implémentation d’un validateur personnalisé pour un champ

$callback = function (\muuska\validation\input\ValidationInput $input) {
    $result = null;
    if ($input->getValue() === 'My value') {
        $result = App::validations()->createDefaultValidationResult(true);
    } else {
        $result = App::validations()->createDefaultValidationResult(
            false, 
            [App::translateApp(App::createErrorTranslationConfig(),'My value is required',$input->getLang())]
        );
    }
    return $result;
};
$validator = App::validations()->createDefaultValidator($callback);

'description' => array(
    'type' => DataType::TYPE_STRING,
    'nature' => FieldNature::LONG_TEXT,
    'validator' => $validator
)

Création des options pour un champ

Ajouter un dossier option dans votre application puis ajouter La classe de votre option

<?php
namespace myapp\option;

use muuska\option\provider\AbstractOptionProvider;
use myapp\constants\Accessibility;

class AccessibilityProvider extends AbstractOptionProvider
{
    protected function initOptions()
    {
        $this->addArrayOption(Accessibility::PUBLIC, $this->l('Public'));
        $this->addArrayOption(Accessibility::PRIVATE, $this->l('Private'));
    }
}

La méthode initOptions vous permet d’initialiser vos options. Grace à la méthode addArrayOption, vous pouvez ajouter vos options, le premier paramètre représente la valeur de l’option, et le deuxième le label de l’option. Il faut utiliser la méthode « l » pour obtenir la traduction d’un texte.

Définition d’un champ externe

'addressId' => array(
    'type' => DataType::TYPE_INT,
    'nature' => FieldNature::EXISTING_MODEL_ID,
    'required' => true,
    'reference' => AddressDefinition::getInstance(),
    'onDelete' => ReferenceOption::CASCADE
),

g. Utilisation d’un tableau associatif comme model

Vous n’êtes pas obligé de créer une classe model pour toutes vos définitions. Vous pouvez spécifier dans la définition que vous voulez qu’un tableau associatif soit créé. Pour le faire vous devez ajouter l’instruction suivante dans la définition :

'modelType' => self::MODEL_TYPE_ARRAY,

Une fois cette instruction ajoutée, à chaque fois qu’une voudra une instance du model, une instance de la classe muuska\model\ArrayModel sera retourné.
Cette classe contient les méthodes suivantes :

getPropertyValue

Permet d’obtenir la valeur d’une propriété. Elle prend en paramètre le nom de la propriété.

setPropertyValue

Permet de modifier la valeur d’une propriété, elle prend en paramètre de nom de la propriété et la nouvelle valeur.

La définition finale de l’objet sera :

<?php
namespace myapp\model;

use muuska\constants\DataType;
use muuska\constants\FieldNature;
use muuska\dao\constants\ReferenceOption;
use muuska\model\AbstractModelDefinition;

class  CategoryDefinition extends AbstractModelDefinition
{

    protected static $instance;

    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new static();
        }
        return self::$instance;
    }

    protected function createDefinition()
    {
        return array(
            'name' => 'category',
            'primary' => 'id',
            'autoIncrement' => true,
            'fields' => array(
                'parentId' => array(
                    'type' => DataType::TYPE_INT,
                    'nature' => FieldNature::EXISTING_MODEL_ID,
                    'reference' => static::getInstance(),
                    'onDelete' => ReferenceOption::CASCADE
                ),
                'name' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::NAME,
                    'required' => true,
                    'maxSize' => 200
                ),
                'image' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::IMAGE,
                    'maxSize' => 50
                ),
                'description' => array(
                    'type' => DataType::TYPE_STRING,
                    'nature' => FieldNature::LONG_TEXT
                )
            )
        );
    }
}

2. Notion de model

C’est une classe avec les attributs, méthode, les getters et les setters.
Elle doit hériter de la classe \muuska\model\AbstractModel

<?php
namespace myapp\model;

use muuska\model\AbstractModel;

class Library extends AbstractModel{
	protected $id;
	protected $addressId;
	protected $name;
	protected $openingTime;
	protected $accessibility;
	protected $image;
	protected $description;	

	public function getId(){
		return $this->id;
	}
	public function setId($id){
		$this->id = $id;
	}
	public function getAddressId(){
		return $this->addressId;
	}
	public function setAddressId($addressId){
		$this->addressId = $addressId;
	}
	public function getName(){
		return $this->name;
	}
	public function setName($name){
		$this->name = $name;
	}
	public function getOpeningTime(){
		return $this->openingTime;
	}
	public function setOpeningTime($openingTime){
		$this->openingTime = $openingTime;
	}
	public function getAccessibility(){
		return $this->accessibility;
	}
	public function setAccessibility($accessibility){
		$this->accessibility = $accessibility;
	}
	public function getImage(){
		return $this->image;
	}
	public function setImage($image){
		$this->image = $image;
	}
	public function getDescription(){
		return $this->description;
	}
	public function setDescription($description){
		$this->description = $description;
	}
}

La classe AbstractModel contient les méthodes suivantes :

a. setAssociated

Permet de modifier l’instance d’un objet externe. Elle prend en paramètre le nom du champ sur lequel la référence de l’objet est définit et l’instance du nouvel objet.

b. getAssociated

Permet d’obtenir l’instance d’un objet externe. Elle prend en paramètre le nom du champ sur lequel la référence de l’objet est définit.

c. hasAssociated

Permet de vérifier si l’instance d’un objet externe existe. Elle prend en paramètre le nom du champ sur lequel la référence de l’objet est définit.

d. addMultipleAssociated

Permet d’ajouter un objet à une association multiple. Elle prend en paramètre le nom de l’association multiple et l’instance de l’objet.

e. setMultipleAssociatedModels

Permet modifier les instances d’une association multiple. Elle prend en paramètre le nom de l’association multiple et un tableau d’objet.

f. getMultipleAssociatedModels

Permet d’obtenir les instances d’une association multiple. Elle prend en paramètre le nom de l’association multiple.

3. Test des model

Nous allons créer un contrôler « test-model » pour tester nos Models.

a. Création du contrôler test-model

Allez dans votre dossier controller/front et créer une classe TestModelController

<?php
namespace myapp\controller\front;

use muuska\controller\AbstractController;

class TestModelController extends AbstractController
{
    protected function processDefault()
    {
        
    }
}

b. Modification de la classe FrontSubApplication

<?php
namespace myapp;

use muuska\project\AbstractSubApplication;

class FrontSubApplication extends AbstractSubApplication
{
    public function createController(\muuska\controller\ControllerInput $input) {
        $result = null;
        if ($input->checkName('hello-world')) {
            $result = new \myapp\controller\front\HelloWorldController($input);
        }elseif ($input->checkName('test-model')) {
            $result = new \myapp\controller\front\TestModelController($input);
        }
        return $result;
    }
}

Entrez l’url http://localhost/muuska/fr/test-model pour y accéder

c. Code de test

<?php
namespace myapp\controller\front;

use muuska\controller\AbstractController;
use myapp\model\Library;
use myapp\constants\Accessibility;
use myapp\model\AddressDefinition;
use myapp\model\SpecialityDefinition;

class TestModelController extends AbstractController
{
    protected function processDefault()
    {
        /*Création de la bibliotheque*/
        $library = new Library();
        $library->setName('My library');
        $library->setOpeningTime('Monday');
        $library->setAccessibility(Accessibility::PUBLIC);
        $library->setDescription('My library desc');
        
        /*Création de l'adresse*/
        $address = AddressDefinition::getInstance()->createModel();
        $address->setPropertyValue('address', '4500 NY');
        $address->setPropertyValue('city', 'New york');
        $address->setPropertyValue('state', 'New york');
        $address->setPropertyValue('country', 'US');
        
        /*Création de la specialité*/
        $speciality1 = SpecialityDefinition::getInstance()->createModel();
        $speciality1->setPropertyValue('name', 'Art');
        
        $speciality2 = SpecialityDefinition::getInstance()->createModel();
        $speciality2->setPropertyValue('name', 'Musique');
        
        /*Modification de l'adresse de la bibliotheque*/
        $library->setAssociated('addressId', $address);
        
        /*Ajout des specialités a la bibliotheque*/
        $library->addMultipleAssociated('specialities', $speciality1);
        $library->addMultipleAssociated('specialities', $speciality2);
        
        /*Affichage*/
        var_dump('bibliotheque : ', $library);
        var_dump('adresse : ', $library->getAssociated('addressId'));;
        var_dump('specialités : ', $library->getMultipleAssociatedModels('specialities'));
    }
}

4. Déploiement des models

Pour déployer les models sur le support d’accès aux données, vous devez faire une mise à jour de votre application en suivant les étapes suivantes :

a. Créer le processus de mise à jour

Ouvrez la classe MyApp et redéfinissez la méthode createUpgrade

AbstractApplication.php
<?php
namespace myapp;

use muuska\project\AbstractApplication;
use muuska\util\App;
use muuska\project\constants\SubAppName;

class MyApp extends AbstractApplication
{
    protected function registerMainDAOSources(){
        parent::registerMainDAOSources();
        $this->registerDaoSource(App::daos()->createPDOSourceFromConfiguration());
    }
    
    protected function createSubProject($subAppName){
        if($subAppName === SubAppName::FRONT_OFFICE){
            return new FrontSubApplication($subAppName, $this);
        }
    }
    
    protected function createAppSetup()
    {
        return new \myapp\setup\AppSetup($this);
    }
    
    protected function createUpgrade(){
        
    }
}

Puis ajouter le code suivant :

protected function createUpgrade(){
    $daoInput = App::daos()->createProjectDAOUpgradeInput($this);
    $daoInput->addAddedModelDefinition(SpecialityDefinition::getInstance());
    $daoInput->addAddedModelDefinition(TypeDefinition::getInstance());
    $daoInput->addAddedModelDefinition(AddressDefinition::getInstance());
    $daoInput->addAddedModelDefinition(CategoryDefinition::getInstance());
    $daoInput->addAddedModelDefinition(PublisherDefinition::getInstance());
    $daoInput->addAddedModelDefinition(AuthorDefinition::getInstance());
    $daoInput->addAddedModelDefinition(LibraryDefinition::getInstance());
    $daoInput->addAddedModelDefinition(LibraryTypeDefinition::getInstance());
    $daoInput->addAddedModelDefinition(LibrarySpecialityDefinition::getInstance());
    $daoInput->addAddedModelDefinition(BookDefinition::getInstance());
    return App::projects()->createDefaultProjectUpgrade($this, $this->daoFactory, $daoInput);
}

b. Modifier la version de l’application

Il faut modifier la version de l’application afin que la mise à jour puisse se lancer automatiquement à la prochaine exécution de l’application. Pour le faire il faut ajouter l’instruction suivante dans la classe MyApp

protected $version = '1.1';

c. Code finale de l’application

<?php
namespace myapp;

use muuska\project\AbstractApplication;
use muuska\util\App;
use muuska\project\constants\SubAppName;
use myapp\model\SpecialityDefinition;
use myapp\model\TypeDefinition;
use myapp\model\AddressDefinition;
use myapp\model\CategoryDefinition;
use myapp\model\PublisherDefinition;
use myapp\model\AuthorDefinition;
use myapp\model\LibraryDefinition;
use myapp\model\LibraryTypeDefinition;
use myapp\model\LibrarySpecialityDefinition;
use myapp\model\BookDefinition;

class MyApp extends AbstractApplication
{
    protected $version = '1.1';
    
    protected function registerMainDAOSources(){
        parent::registerMainDAOSources();
        $this->registerDaoSource(App::daos()->createPDOSourceFromConfiguration());
    }
    protected function createSubProject($subAppName){
        if($subAppName === SubAppName::FRONT_OFFICE){
            return new FrontSubApplication($subAppName, $this);
        }
    }
    protected function createAppSetup()
    {
        return new \myapp\setup\AppSetup($this);
    }
    
    protected function createUpgrade(){
        $daoInput = App::daos()->createProjectDAOUpgradeInput($this);
        $daoInput->addAddedModelDefinition(SpecialityDefinition::getInstance());
        $daoInput->addAddedModelDefinition(TypeDefinition::getInstance());
        $daoInput->addAddedModelDefinition(AddressDefinition::getInstance());
        $daoInput->addAddedModelDefinition(CategoryDefinition::getInstance());
        $daoInput->addAddedModelDefinition(PublisherDefinition::getInstance());
        $daoInput->addAddedModelDefinition(AuthorDefinition::getInstance());
        $daoInput->addAddedModelDefinition(LibraryDefinition::getInstance());
        $daoInput->addAddedModelDefinition(LibraryTypeDefinition::getInstance());
        $daoInput->addAddedModelDefinition(LibrarySpecialityDefinition::getInstance());
        $daoInput->addAddedModelDefinition(BookDefinition::getInstance());
        return App::projects()->createDefaultProjectUpgrade($this, $this->daoFactory, $daoInput);
    }
}

d. Démarrer la mise à jour

Lancer n’importe quel contrôleur de votre application. Le support d’accès aux données courant (Base de données) fera la mise à jour de votre application. Pour vérifier, ouvrez votre client de base de donnée vous verrez vos tables ajouté avec le préfix "msk_a_“.

database_books

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *