Il est fortement recommandé d'utiliser flightphp/active-record au lieu de cette bibliothèque. Aucun développement ultérieur ne sera effectué avec cette bibliothèque, mais elle fonctionne telle qu'elle est actuellement.
super model est une classe php de type ORM très simple pour interagir facilement avec les tables d'une base de données sans écrire une tonne de code SQL partout.
Pour le prouver, voici les lignes de code...
$ cloc src/
1 text file.
1 unique file.
0 files ignored.
github.com/AlDanial/cloc v 1.74 T=0.01 s (71.8 files/s, 48768.5 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
PHP 1 86 246 347
-------------------------------------------------------------------------------
Ceci est écrit dans un souci de performance. Ainsi, même s'il ne satisfera pas à toutes les exigences de chaque projet jamais construit, il fonctionnera dans la majorité des cas et fera également un excellent travail !
Démarrer avec super model est simple, il suffit d'étendre la classe super model et de définir un nom de table. C'est à peu près tout.
<?php
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
}
Et maintenant, que diriez-vous de quelques exemples simples de sa façon de travailler ?
Tout d’abord, supposons le tableau suivant :
Table: users
---------------------------------------------------------
| id | email | company_id |
| 1 | [email protected] | 50 |
| 2 | [email protected] | 61 |
| 3 | [email protected] | 61 |
---------------------------------------------------------
<?php
// somefile.php
$ pdo = new PDO ( ' sqlite::memory: ' , '' , '' , [ PDO :: ATTR_DEFAULT_FETCH_MODE => PDO :: FETCH_ASSOC ]);
$ User = new User ( $ pdo );
// WHERE company_id = 50
$ users = $ User -> getAllBycompany_id ( 50 );
// same as above
$ users = $ User -> getAll ([ ' company_id ' => 50 ]);
Un petit pois facile, un jus de citron, n'est-ce pas ?
getBy*(mixed $value): array [result]
Il s'agit d'une méthode qui renvoie une ligne en arrière à partir de la valeur spécifiée. La partie *
de la méthode fait référence à un champ de la base de données. Le nom du champ est sensible à la casse, quel que soit le nom de votre champ dans votre table de base de données.
// get by the id field on the users table
$ User -> getByid ( 3 );
/*
[
'id' => 3,
'email' => '[email protected]',
'company_id' => 61
]
*/
$ User -> getBycompany_id ( 61 );
/*
// it only will pull the first row, not all rows
[
'id' => 2,
'email' => '[email protected]',
'company_id' => 61
]
*/
getAllBy*(mixed $value): array [ [result], [result] ]
Il s'agit d'un filtre de raccourci pour renvoyer toutes les lignes selon une valeur donnée. La partie *
de la méthode fait référence à un champ de la base de données. Le nom du champ est sensible à la casse, quel que soit le nom de votre champ dans votre table de base de données.
// this is pointless, but will still work
$ User -> getAllByid ( 3 );
/*
[
[
'id' => 3,
'email' => '[email protected]',
'company_id' => 61
]
]
*/
$ User -> getAllBycompany_id ( 61 );
/*
[
[
'id' => 2,
'email' => '[email protected]',
'company_id' => 61
],
[
'id' => 3,
'email' => '[email protected]',
'company_id' => 61
]
]
*/
getAll(array $filters, bool $return_one_row = false): array [ [result], [result] ] or [result]
Il s'agit du filtre dans lequel vous pouvez ajouter de nombreuses personnalisations pour filtrer les données de votre table. Il existe quelques clés uniques à connaître et certains opérateurs pour vous aider à extraire vos données spécifiques.
// Full example
$ filters = [
//
// arguments in the WHERE statement
//
' some_field ' => 5 , // some_field = ?
' some_field-= ' => 5 , // some_field = ?
' another_field ' => ' IS NULL ' , // some_field IS NULL
' another_field ' => ' IS NOT NULL ' , // some_field IS NOT NULL
' another_field-> ' => ' Apple ' , // another_field > ?
' another_field->= ' => ' Apple ' , // another_field >= ?
' another_field-< ' => ' Apple ' , // another_field < ?
' another_field-<= ' => ' Apple ' , // another_field <= ?
' another_field-!= ' => ' Apple ' , // another_field != ?
' another_field-<> ' => ' Apple ' , // another_field <> ?
' another_field-LIKE ' => ' Ap%ple ' , // another_field LIKE ?
' another_field-NOT LIKE ' => ' Apple% ' , // another_field NOT LIKE ?
' another_field-IN ' => [ ' Apple ' , ' Banana ' , ' Peach ' ], // another_field IN(??) double question mark gets parsed as array
' another_field-NOT IN ' => [ ' Apple ' , ' Banana ' , ' Peach ' ], // another_field NOT IN(??) double question mark gets parsed as array
// If you need some custom action
' another_field-RAW-> DATE_SUB(?, INTERVAL 1 DAY) ' => ' 1980-01-01 ' , // another_field > DATE_SUB(?, INTERVAL 1 DAY)
//
// Other parts of the query
//
// choose what columns you want to select
' select_fields ' => ' id, first_name ' ,
// Get any joins
' joins ' => [ ' LEFT JOIN companies ON companies.id = users.company_id ' ],
// Group by
' group_by ' => ' company_id ' ,
// having
' having ' => ' count > 5 ' ,
// order by
' order_by ' => ' id DESC ' ,
// limit
' limit ' => 15 ,
// offset
' offset ' => 10000 ,
];
$ users = $ User -> getAll ( $ filters );
Il existe également quelques options de configuration de base avec les propriétés du modèle.
Si vous disposez d'un modèle dont vous savez qu'il renverra toujours un petit jeu de résultats et que vous souhaitez pouvoir interroger la table entière, définissez cette propriété. Sinon, il s'agit d'une protection de sorte que si aucun paramètre SQL n'est fourni, vous ne récupérerez pas l'intégralité du jeu de résultats (ce qui pourrait planter et graver beaucoup de choses).
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
protected $ disallow_wide_open_queries = false ;
}
create(array $data): int [insert id]
Cela créera une seule ligne sur la table, mais si vous fournissez un tableau multidimensionnel, plusieurs lignes seront insérées. Une clé primaire d' id
est supposée.
$ User -> create ([ ' email ' => ' [email protected] ' , ' company_id ' => 55 ]);
// returns 4
$ User -> create ([ [ ' email ' => ' [email protected] ' , ' company_id ' => 55 ], [ ' email ' => ' [email protected] ' , ' company_id ' => 56 ] ]);
// returns 6, only the last id will be returned
update(array $data, string $update_field = 'id'): int (number of rows updated)
Cela créera une seule ligne sur la table, mais si vous fournissez un tableau multidimensionnel, plusieurs lignes seront insérées. Une clé primaire d' id
est supposée.
$ User -> update ([ ' id ' => 1 , ' email ' => ' [email protected] ' ]);
// returns 1 and will only update the email field
$ User -> update ([ ' email ' => ' [email protected] ' , ' company_id ' => 61 ], ' email ' );
// returns 1
$ User -> update ([ ' company_id ' => 61 , ' email ' => ' [email protected] ' ], ' company_id ' );
// returns 3, not really logical, but it would update all the emails
Que se passe-t-il si vous souhaitez un moyen automatisé de modifier votre résultat si un indicateur spécifique est déclenché ? Très facile. Il existe une méthode appelée processResult()
qui parcourra chaque résultat que vous extrayez. Vous injectez des filtres spéciaux pour cette méthode dans la clé $filters['processResults']
.
<?php
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
public processResult (array $ process_filters , array $ result ): array {
// add some trigger here and do whatever checks you need
if( isset ( $ process_filters ['set_full_name']) && $ process_filters ['set_full_name'] === true && !empty( $ result ['first_name']) && !empty( $ result ['last_name'])) {
$ result ['full_name'] = $ result [ ' first_name ' ]. ' ' . $ result [ ' last_name ' ];
}
return $ result ;
}
}
// later on in some other file.
$ User = new User ( $ pdo );
// setting the processResults filter here is the key to connecting the getAll statement with your processResult method
$ users = $ User -> getAll ([ ' company_id ' => 51 , ' processResults ' => [ ' set_full_name ' => true ] ]);
echo $ users [ 0 ][ ' full_name ' ]; // Bob Smith
Que se passe-t-il si vous devez effectuer une requête SQL complexe et folle qui ne relève pas du domaine de cette classe ou des filtres getAll()
?
N'oubliez pas que le but de ce cours n'est PAS de satisfaire toutes les exigences de chaque projet qui a existé ou existera, mais il vous permettra d'y parvenir à 90 %. À la lumière de cela, il existe un moyen simple de répondre à la question ci-dessus. Utilisez simplement RAW SQL pour votre unique.
<?php
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
public function processCrazyKukooQuery ( /* add whatever required fields you need */ ): array {
$ db = $ this -> getDbConnection ();
// shamelessly ripped from StackOverflow
$ statement = $ db -> prepare ( " SELECT
DISTINCT
t.id,
t.tag,
c.title AS Category
FROM
tags2Articles t2a
INNER JOIN tags t ON t.id = t2a.idTag
INNER JOIN categories c ON t.tagCategory = c.id
INNER JOIN (
SELECT
a.id
FROM
articles AS a
JOIN tags2articles AS ta ON a.id=ta.idArticle
JOIN tags AS tsub ON ta.idTag=tsub.id
WHERE
tsub.id IN (12,13,16)
GROUP BY a.id
HAVING COUNT(DISTINCT tsub.id)=3
) asub ON t2a.idArticle = asub.id " );
$ statement -> execute ();
return $ statement -> fetchAll ();
}
}
Exécutez simplement composer test
pour exécuter phpunit
et phpstan
. Actuellement à 100% de couverture et c'est là que j'aimerais le garder.
Remarque concernant la couverture à 100 % : même si le code peut avoir une couverture à 100 %, la couverture réelle est différente. L'objectif est de tester de nombreux scénarios différents par rapport au code pour réfléchir au code et anticiper les résultats inattendus. Je code sur une couverture « réelle », et non sur une couverture « le code a-t-il été exécuté ».