Se recomienda encarecidamente que utilice Flightphp/active-record en lugar de esta biblioteca. No se realizarán más desarrollos con esta biblioteca, pero funciona como está ahora.
super model es una clase PHP de tipo ORM muy simple para interactuar fácilmente con tablas en una base de datos sin escribir una tonelada de código SQL por todos lados.
Para demostrarlo, aquí están las líneas de código...
$ 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
-------------------------------------------------------------------------------
Esto está escrito pensando en el rendimiento. Entonces, si bien no satisfará todos los requisitos de todos los proyectos que se hayan construido, funcionará en la mayoría de los casos, ¡y también hará un gran trabajo!
Comenzar con super model es fácil: simplemente extienda la clase super model y defina un nombre de tabla. Eso es todo.
<?php
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
}
¿Y ahora qué tal algunos ejemplos sencillos de cómo trabaja?
Primero, supongamos la siguiente tabla:
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 ]);
Fácil, exprimido de limón, ¿verdad?
getBy*(mixed $value): array [result]
Este es un método que devuelve una fila atrás del valor especificado. La parte *
del método se refiere a un campo en la base de datos. El nombre del campo distingue entre mayúsculas y minúsculas según el nombre de su campo en la tabla de su base de datos.
// 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] ]
Este es un filtro de acceso directo para devolver todas las filas por un valor determinado. La parte *
del método se refiere a un campo en la base de datos. El nombre del campo distingue entre mayúsculas y minúsculas según el nombre de su campo en la tabla de su base de datos.
// 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]
Este es el filtro donde puede agregar un montón de personalizaciones para filtrar los datos de su tabla. Hay algunas claves únicas que debe tener en cuenta y algunos operadores que le ayudarán a extraer sus datos específicos.
// 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 );
También hay algunas opciones de configuración básicas con las propiedades del modelo.
Si tiene un modelo que sabe que siempre devolverá un pequeño conjunto de resultados y desea poder consultar la tabla completa, establezca esta propiedad. De lo contrario, es una protección de modo que si no se proporcionaron parámetros SQL, no recuperará todo el conjunto de resultados (lo que podría fallar y quemar muchas cosas).
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
protected $ disallow_wide_open_queries = false ;
}
create(array $data): int [insert id]
Esto creará una sola fila en la tabla, pero si proporciona una matriz multidimensional, se insertarán varias filas. Se supone una clave primaria de id
.
$ 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)
Esto creará una sola fila en la tabla, pero si proporciona una matriz multidimensional, se insertarán varias filas. Se supone una clave primaria de id
.
$ 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
¿Qué sucede si desea una forma automatizada de alterar su resultado si se activa una bandera específica? Fácil. Hay un método llamado processResult()
que ejecutará cada resultado que obtenga. Inyecta filtros especiales para este método en la clave $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
¿Qué sucede si necesita realizar una consulta SQL compleja y loca que no entra en el ámbito de esta clase o de los filtros getAll()
?
Recuerde que el objetivo de esta clase NO es satisfacer todos los requisitos de cada proyecto que haya existido o que exista, pero lo llevará al 90% del camino hasta allí. En vista de esto, existe una manera sencilla de ejecutar la pregunta anterior. Simplemente use SQL RAW para su única vez.
<?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 ();
}
}
Simplemente ejecute composer test
para ejecutar phpunit
y phpstan
. Actualmente con una cobertura del 100% y ahí es donde me gustaría mantenerlo.
Una nota sobre la cobertura del 100%: si bien el código puede tener una cobertura del 100%, la cobertura real es diferente. El objetivo es probar muchos escenarios diferentes con el código para analizarlo y anticipar resultados inesperados. Codifico para una cobertura "real", no para una cobertura de "ejecución del código".