强烈建议您使用 Flightphp/active-record 而不是这个库。该库不会进行进一步的开发,但它确实可以像现在一样工作。
super model是一个非常简单的 ORM 类型 php 类,可以轻松地与数据库中的表进行交互,而无需到处编写大量 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()
的方法,它将运行您拉回的每个结果。您可以在$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% 覆盖率,但实际覆盖率是不同的。目标是针对代码测试许多不同的场景,以深入思考代码并预测意外结果。我对“真实”覆盖率进行编码,而不是“代码是否运行”覆盖率。