Настоятельно рекомендуется использовать Flightphp/active-record вместо этой библиотеки. Никакого дальнейшего развития этой библиотеки не будет, но она работает так, как сейчас.
super model — это очень простой PHP-класс типа ORM, позволяющий легко взаимодействовать с таблицами в базе данных без написания повсюду тонны кода SQL.
Чтобы доказать это, вот строки кода...
$ 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
-------------------------------------------------------------------------------
Это написано с учетом производительности. Таким образом, хотя он и не будет удовлетворять всем требованиям каждого когда-либо созданного проекта, он будет работать в большинстве случаев и отлично справится с этой задачей!
Начать работу с super model легко: просто расширите класс super model и определите имя таблицы. Вот и все.
<?php
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
}
А как насчет простых примеров того, как она работает?
Во-первых, давайте предположим следующую таблицу:
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 ]);
Легко, лимонная выжимка, правда?
getBy*(mixed $value): array [result]
Это метод, который возвращает одну строку назад от указанного значения. Часть метода *
относится к полю в базе данных. Имя поля чувствительно к регистру, независимо от имени вашего поля в таблице базы данных.
// 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] ]
Это быстрый фильтр для возврата всех строк по заданному значению. Часть метода *
относится к полю в базе данных. Имя поля чувствительно к регистру, независимо от имени вашего поля в таблице базы данных.
// 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]
Это фильтр, в который вы можете добавить множество настроек для фильтрации данных из вашей таблицы. Есть несколько уникальных ключей, о которых следует знать, и несколько операторов, которые помогут вам получить конкретные данные.
// 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 );
Существуют также некоторые базовые параметры конфигурации свойств модели.
Если у вас есть модель, которая, как вы знаете, всегда будет возвращать небольшой набор результатов и вы хотите иметь возможность запрашивать всю таблицу, установите это свойство. В противном случае это защита, так что, если не были указаны параметры sql, вы не получите обратно весь набор результатов (что может привести к сбою и сгоранию многих вещей).
use n0nag0n Super_Model ;
class User extends Super_Model {
protected $ table = ' users ' ;
protected $ disallow_wide_open_queries = false ;
}
create(array $data): int [insert id]
Это создаст одну строку в таблице, но если вы предоставите многомерный массив, будет вставлено несколько строк. Предполагается первичный ключ 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)
Это создаст одну строку в таблице, но если вы предоставите многомерный массив, будет вставлено несколько строк. Предполагается первичный ключ 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
Что делать, если вам нужен автоматизированный способ изменить результат при срабатывании определенного флага? Легко, просто. Существует метод под названиемprocessResult processResult()
, который будет обрабатывать каждый результат, который вы возвращаете. Вы добавляете специальные фильтры для этого метода в ключ $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
Что, если вам нужно выполнить безумно сложный SQL-запрос, который не подпадает под действие этого класса или фильтров getAll()
?
Помните, что цель этого класса НЕ в том, чтобы удовлетворить все требования каждого проекта, который когда-либо существовал или будет существовать, но он поможет вам достичь цели на 90%. В свете этого есть простой способ выполнить приведенный выше вопрос. Просто используйте RAW SQL в качестве единственного случая.
<?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 ();
}
}
Просто запустите composer test
, чтобы запустить phpunit
и phpstan
. В настоящее время покрытие составляет 100%, и я хотел бы сохранить его на этом уровне.
Примечание о 100-процентном покрытии: хотя код может иметь 100-процентное покрытие, фактическое покрытие отличается. Цель состоит в том, чтобы протестировать множество различных сценариев на основе кода, чтобы продумать код и предвидеть неожиданные результаты. Я кодирую для «реального» покрытия, а не для покрытия «работает ли код».