Travailler avec des modèles (Avancé)
====================================
Modes d'hydratation de données
------------------------------
Comme mentionné plus haut, les jeux de résultat sont des collections complètes d'objets, ce qui signifie que chaque résultat renvoyé est un objet
qui représente une ligne dans la base de données. Ces objets peuvent être modifiés et re-sauvegardés pour la persistence:
.. code-block:: php
year = 2000;
$robot->save();
}
Parfois les enregistrement récupérés ne doivent être présentées à l'utilisateur qu'en lecture seule. Dans ces cas il peut être utile
de changer la manière dont les enregistrement sont présentés afin de faciliter leur manipulation. La statégie utilisée pour présenter
les objets retournés dans un jeu de résultat est appelée "mode d'hydratation":
.. code-block:: php
setHydrateMode(
Resultset::HYDRATE_ARRAYS
);
foreach ($robots as $robot) {
echo $robot["year"], PHP_EOL;
}
// Retourne tous les robots dans une stdClass
$robots->setHydrateMode(
Resultset::HYDRATE_OBJECTS
);
foreach ($robots as $robot) {
echo $robot->year, PHP_EOL;
}
// Retourne tous les robots dans une instance de Robots
$robots->setHydrateMode(
Resultset::HYDRATE_RECORDS
);
foreach ($robots as $robot) {
echo $robot->year, PHP_EOL;
}
Le mode d'hydratation peut également être transmis en paramètre de "find":
.. code-block:: php
Resultset::HYDRATE_ARRAYS,
]
);
foreach ($robots as $robot) {
echo $robot["year"], PHP_EOL;
}
Les colonnes identité auto-générées
-----------------------------------
Certains modèles peuvent avoir une colonne identité. Ces colonnes servent habituellement de clé primaire dans la table rattachée. :doc:`Phalcon\\Mvc\\Model <../api/Phalcon_Mvc_Model>`
peut reconnaître la colonne identité et l'omet dans l'instruction SQL INSERT générée, laissant le SGBD générer ainsi automatiquement la valeur pour lui.
Systématiquement après chaque création d'enregistrement, le champ identité est rempli avec la valeur générée par le SGBD:
.. code-block:: php
save();
echo "The generated id is: ", $robot->id;
:doc:`Phalcon\\Mvc\\Model <../api/Phalcon_Mvc_Model>` est capable de reconnaître la colonne identité. Selon le SGBD, ces colonnes peut être des
colonnes "serial" comme dans PostgreSQL ou "auto_increment" dans le cas de MySQL.
PostgreSQL utilise les séquences pour générer des valeurs numérique. Par défaut, Phalcon tente d'obtenir les valeurs depuis la séquence "
__seq",
comme par exemple "robots_id_seq". Si cette séquence a un nom différent, alors la méthode "getSequenceName" doit être réalisée:
.. code-block:: php
` qu'il doit omettre systématiquement des champs lors de la création ou la mise à jour d'enregistrement
afin de déléguer au SGDB la mission d'assigner les valeurs soit par défaut soit par l'intermédiaire d'un déclencheur:
.. code-block:: php
skipAttributes(
[
"year",
"price",
]
);
// Omis uniquement à la création
$this->skipAttributesOnCreate(
[
"created_at",
]
);
// Omis uniquement à la mise à jour
$this->skipAttributesOnUpdate(
[
"modified_in",
]
);
}
}
Ceci ignorera ces champs sur chaque opération d'INSERT ou d'UPDATE pour l'ensemble de l'application.
Si vous voulez ignorer des attributs selon l'opération INSERT ou UPDATE, vous devez spécifier un dexuième paramètre (booléen) - vrai pour le
remplacement. Forcer une nouvelle valeur par défaut peut être réalisée de la façon suivante:
.. code-block:: php
name = "Bender";
$robot->year = 1999;
$robot->created_at = new RawValue("default");
$robot->create();
Une fonction de rappel peut être utilisée pour réaliser une assignation conditionnelle des valeurs par défaut:
.. code-block:: php
price > 10000) {
$this->type = new RawValue("default");
}
}
}
.. highlights::
N'utilisez jamais :doc:`Phalcon\\Db\\RawValue <../api/Phalcon_Db_RawValue>` pour assigner des valeurs externes (comme les entrées utilisateur)
ou des données variables. Les valeurs de ces champs sont ignorées lors de la liaison de paramètres à la requête.
Ceci peut être sujet à des attaques par injection SQL.
Mise à jour dynamique
^^^^^^^^^^^^^^^^^^^^^
Par défaut, les instructions SQL UPDATE sont créées avec toutes les colonnes définies dans le modèle (full all-field SQL update).
Vous pouvez modifier des modèles spécifique pour réaliser des mises à jour dynamiques. Dans ce cas, seuls les champs qui ont changé
seront utilisés dans l'instruction SQL finale.
Dans certains cas, cela peut améliorer les performances en réduisant le trafic entre l'application et le serveur de base de données.
Ceci est particulièrement utiles lorsque la table contient des champs blob ou textuels:
.. code-block:: php
useDynamicUpdate(true);
}
}
Correspondance indépendante de colonnes
---------------------------------------
L'ORM supporte une correspondance indépendante de colonnes, ce qui permet au développeur d'utiliser des noms de colonnes dans le modèles différents de ceux
de la table. Phalcon reconnaîtra les nouveaux noms de colonnes et les renommera pour qu'ils correspondent aux colonnes respectives dans la base.
Ceci est une caractéristique intéressante lorsqu'on a besoin de renommer des champs sans avoir à se soucier de toutes les requêtes
du code. Un simple changement dans la correspondance de colonnes et le modèle s'occupera du reste. Par exemple:
.. code-block:: php
"code",
"the_name" => "theName",
"the_type" => "theType",
"the_year" => "theYear",
];
}
}
Ainsi vous pouvez utilisez simplement les nouveaux noms dans votre code:
.. code-block:: php
theName, "\n";
// Récupérer les robots triés par type
$robot = Robots::find(
[
"order" => "theType DESC",
]
);
foreach ($robots as $robot) {
echo "Code: ", $robot->code, "\n";
}
// Création d'un robot
$robot = new Robots();
$robot->code = "10101";
$robot->theName = "Bender";
$robot->theType = "Industrial";
$robot->theYear = 2999;
$robot->save();
Prenez en considération ce qui suit lors du renommage de colonnes:
* Les références aux attributs dans les relations et validateurs doivent utiliser les nouveaux noms
* Se référer au nom réel résultera en une exception de la part de l'ORM
La correspondance indépendante de colonnes vous permet:
* D'écrire des application en utilisant vos propre conventions
* D'éliminer les suffixe ou préfixe dans votre code
* De renommer les colonnes sans avoir à modifier le code de votre application
Instantanés d'enregistrements
-----------------------------
Des modèles spéciaux peuvent être définis pour maintenir un instantané d'enregistrements lors de l'interrogation. Vous pouvez utiliser cette caractéristique pour
mettre en œuvre un audit ou bien juste pour savoir quels sont les champs qui ont changés depuis leur dernière interrogation:
.. code-block:: php
keepSnapshots(true);
}
}
En activant cette caractéristique, l'application consomme un peu plus de mémoire pour conserver les valeurs d'origine obtenues depuis la persistance.
Dans les modèles qui ont activés cette caractéristique vous pouvez vérifier quels sont les champs qui ont changé:
.. code-block:: php
name = "Other name";
var_dump($robot->getChangedFields()); // ["name"]
var_dump($robot->hasChanged("name")); // true
var_dump($robot->hasChanged("type")); // false
Pointer un schéma différent
---------------------------
Si un modèle est rattaché à une table qui se trouve dans un autre schéma ou base que celui par défaut, vous pouvez utiliser la méthode :code:`setSchema()` pour définir cela:
.. code-block:: php
setSchema("toys");
}
}
Définition de plusieurs bases de données
----------------------------------------
Dans Phalcon, tous les modèles peuvent dépendre de la même connexion à la base de données ou en avoir un particulier. Actuellement,
lorsque :doc:`Phalcon\\Mvc\\Model <../api/Phalcon_Mvc_Model>` a besoin de se connecter à la base, il interroge le service "db" dans le
container de services de l'application. Vous pouvez surcharger le paramétrage de ce service dans la méthode :code:`initialize()`:
.. code-block:: php
set(
"dbMysql",
function () {
return new MysqlPdo(
[
"host" => "localhost",
"username" => "root",
"password" => "secret",
"dbname" => "invo",
]
);
}
);
// Ce service retourne une base de données PostgreSQL
$di->set(
"dbPostgres",
function () {
return new PostgreSQLPdo(
[
"host" => "localhost",
"username" => "postgres",
"password" => "",
"dbname" => "invo",
]
);
}
);
Ainsi, dans la méthode :code:`initialize()`, nous définissons le service de connexion pour le modèle:
.. code-block:: php
setConnectionService("dbPostgres");
}
}
Mais Phalcon offre encore plus de flexibilité, nous pouvons définir une connexion pour la lecture et une pour l'écriture. Ceci est particulièrement utile
pour équilibrer la charge entre les bases de données dans une architecture maître-esclave:
.. code-block:: php
setReadConnectionService("dbSlave");
$this->setWriteConnectionService("dbMaster");
}
}
L'ORM fournit aussi la capacité d'`Horizontal Sharding`_, en vous permettant de mettre en place une sélection de "shard"
en fonction des conditions actuelles de la requête:
.. code-block:: php
0 && $id < 10000) {
return $this->getDI()->get("dbShard1");
}
if ($id > 10000) {
return $this->getDI()->get("dbShard2");
}
}
}
// Utilisation du shard par défaut
return $this->getDI()->get("dbShard0");
}
}
La méthode :code:`selectReadConnection()` est appelée pour sélectionner la bonne connexion. Cette méthode intercepte chaque
nouvelle requête exécutée:
.. code-block:: php
getDI()->getFlash();
$messages = $this->getMessages();
// Affiche les messages de validation
foreach ($messages as $message) {
$flash->error($message);
}
}
}
L'événement "notSaved" est déclenché à chaque échec des actions "create" ou "update". Ainsi nous envoyons les messages de validation
dans le service "flash" obtenu depuis le conteneur DI. En faisant comme cela, nous n'avons par besoin d'imprimer le message après chaque sauvegarde.
Activation/Désactivation de fonctionnalités
-------------------------------------------
Dans l'ORM nous avons mis en place un mécanisme qui vous permette d'activer ou de désactiver à la volée des fonctionnalités particulière ou des options.
Vous pouvez désactiver de que vous n'utilisez pas dans l'ORM. Ces options peuvent également être désactivées temporairement si nécessaire:
.. code-block:: php
false,
"columnRenaming" => false,
]
);
Les options sont:
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| Option | Description | Défaut |
+=====================+=========================================================================================+===============+
| events | Enables/Disables les rappels, crochets et notifications d'événement de tous les modèles | :code:`true` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| columnRenaming | Active/Désactive le renommage de colonnes | :code:`true` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| notNullValidations | L'ORM valide automatiquement les colonnes non nulles présentes dans la table rattachée | :code:`true` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| virtualForeignKeys | Active/Désactive les clés étrangères virtuelles | :code:`true` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| phqlLiterals | Active/Désactive les littéraux dans le parser PHQL | :code:`true` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
| lateStateBinding | Active/Désactive l'état tardif de la méthode :code:`Mvc\Model::cloneResultMap()` | :code:`false` |
+---------------------+-----------------------------------------------------------------------------------------+---------------+
Composant autonome
------------------
L'utilisation de :doc:`Phalcon\\Mvc\\Model ` en mode autonome est montrée ci-dessous:
.. code-block:: php
set(
"db",
new Connection(
[
"dbname" => "sample.db",
]
)
);
// Définition d'un gestionnaire de modèles
$di->set(
"modelsManager",
new ModelsManager()
);
// Utilisation d'un adaptateur de métadonnées
$di->set(
"modelsMetadata",
new MetaData()
);
// Création d'un modèle
class Robots extends Model
{
}
// Utilisation du modèle
echo Robots::count();
.. _Horizontal Sharding: https://en.wikipedia.org/wiki/Shard_(database_architecture)