SCRUD
Abstract class BlackFox\SCRUD (Select|Search, Create, Read, Update, Delete) provides functionality for working with tables in a relational database.
To create a table, you must:
- Create a class descendant of
BlackFox\SCRUD - Describe the table fields in the $fields property
- Add it to the Scheme of the Core and run the Upgrade method
Properties
Name | Description |
---|---|
$name | name of the table or its elements in the plural form |
$code * | symbolic code of the table for use in the database |
$fields | structure of table fields |
$groups | fields groups dictionary, key — code, value — name |
$keys * | codes of primary keys |
$composition * | composition of groups and fields |
$increment * | code of the auto-incrementing field |
By default, the symbolic code for the table in the database is formed in lowercase in the format "Namespace_Class".
If desired, you can override it in the
Table structure
Property
Keys in the dictionary that describes the field type
Name | Description | Types | |
---|---|---|---|
TYPE | string | Symbolic code of the type, list of available types | |
NAME | string | Name | |
GROUP | string | Group | |
NOT_NULL | flag | Prohibit null value | |
INDEX | flag | Index field | |
PRIMARY | flag | Primary key (multiple possible) | |
AUTO_INCREMENT | flag | Incremental field (only one possible) | |
DISABLED | flag | Disable the ability to change the field in the admin section | |
VITAL | flag | Mark field as important, selected by default via '@' | |
VALUES | dictionary | Possible values | SET, ENUM |
LINK | string | Link to another table |
|
FOREIGN | string | Mode of foreign key | OUTER |
... | Other properties depending on type |
$fields = [ 'ID' => self::ID, 'MOMENT' => [ 'TYPE' => 'DATETIME', 'NAME' => 'Moment', 'NOT_NULL' => true, 'DISABLED' => true, ], 'MESSAGE' => [ 'TYPE' => 'TEXT', 'NAME' => 'Message', 'VITAL' => true, ], 'AUTHOR' => [ 'TYPE' => 'OUTER', 'NAME' => 'Author', 'LINK' => 'BlackFox\Users', 'NOT_NULL' => true, 'VITAL' => true, ], 'SCORE' => [ 'TYPE' => 'ENUM', 'NAME' => 'Score', 'VALUES' => [ 'LIKE' => 'Like', 'DISLIKE' => 'Dislike', ], ], ];
Basic methods
Name | Parameters | Description |
---|---|---|
Init |
Runs once in the constructor when a new instance is created
after linking to the database and calculating the $code property,
before running the |
|
Create | $element | Creates a new row in the table and returns its ID. |
Update | $filter, $element | Changes the values of the specified fields in rows that match the filter. |
Delete | $filter | Removes rows that match the filter. |
Read | $filter, $fields, $sort, $escape | Selects the first element that matches the filter. |
Select |
$params - dictionary with keys:
SORT, FILTER, CONDITIONS, FIELDS, LIMIT, PAGE, KEY, ESCAPE, GROUP |
Selects elements page by page, filtering and sorting. Returns a two-dimensional array of elements. |
Search | Selects elements page by page, filtering and sorting. Performs an additional SQL query to find the total number of items that match the filter. Returns a dictionary with keys: ELEMENTS, PAGER. | |
GetColumn | $filter, $field, $sort, $escape | Selects a column by filtering and sorting. Returns a dictionary of elements, in which: key - element identifier, value - the value of the selected element field. |
GetCell | Selects and returns the value of the specified field of the first element matching filter and sorting. |
Usage examples
<?php
// namespace Example; // we are not using namespace here to simplify examples
class Rooms extends \BlackFox\SCRUD {
public $fields = [
'ID' => self::ID,
'TITLE' => [
'TYPE' => 'STRING',
'NAME' => 'Title',
'NOT_NULL' => true,
],
];
}
<?php
// namespace Example; // we are not using namespace here to simplify examples
class Rooms extends \BlackFox\SCRUD {
public function Init() {
$this->fields = [
'ID' => self::ID,
'TITLE' => [
'TYPE' => 'STRING',
'NAME' => T([
'en' => 'Title',
'ru' => 'Название',
]),
'NOT_NULL' => true,
],
];
}
}
<?php
( new \BlackFox\Scheme([Rooms::I()]) )->Synchronize();
$ID = Rooms::I()->Create(['TITLE' => 'Room number 567']);
Rooms::I()->Update(5, ['TITLE' => 'Room number 5']); Rooms::I()->Update([6, 7, 8], ['TITLE' => 'Storage']); Rooms::I()->Update(['TITLE' => 'Unused'], ['TITLE' => 'Gum']);
Rooms::I()->Delete(5); Rooms::I()->Delete([6, 7, 8]); Rooms::I()->Delete(['TITLE' => 'Gum']);
$room = Rooms::I()->Read(5); // $room is array: ['ID' => 5, 'TITLE' => 'Room number 5'] $room = Rooms::I()->Read(5, ['TITLE']); // $room is array: ['TITLE' => 'Room number 5'] $room = Rooms::I()->Read([], ['*'], ['ID' => 'DESC']); // [] means empty condition, ['*'] means all fields, the third param is sort // so the result is gonna be the top element by ID
// each parameter is optional $result = Rooms::I()->Search([ 'FIELDS' => ['ID', 'TITLE'], 'FILTER' => [ 'ID' => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'TITLE' => 'Gum', ], 'LIMIT' => 10, 'PAGE' => 2, ]);
// each parameter is optional $rooms = Rooms::I()->Select([ 'FIELDS' => ['ID', 'TITLE'], 'FILTER' => [ '%TITLE' => $_REQUEST['TITLE'], ], ]);
$result = Rooms::I()->GetColumn([], 'TITLE');
Filter
A filter is an associative array (key — condition + code of the filtered field, value — value of the filter).
The structure of the filter is designed so that it can be passed directly from the form to the model without changes.
It is possible
Instead of an associative array, you can pass
$filter = 15; $filter = [15, 16, 17, 18, 19, 20]; $filter = [ 'MESSAGE' => 'test', '>>MOMENT' => time() - 7 * 24 * 60 * 60, '~AUTHOR.LOGIN' => 'uniko', ];
Fields
Fields is a mixed array. In the simple case, this is a list of selectable fields. If you need to select fields of related elements, add a key (pointing to the linking field) with a value — a list of selectable fields for the associated element.
You can specify a pseudofield:
- @ — all important fields
- * — all fields
$fields = ['@']; $fields = ['*']; $fields = [ 'ID', 'NAME', 'DESCRIPTION', ];
Many-to-one
The
You must specify the
-
LINK — the name of the SCRUD descendant class that describes an external table with a single primary key
namespace BlackFox; class Log extends SCRUD { public $fields = [ 'ID' => self::ID, // ... 'USER' => [ 'TYPE' => 'OUTER', 'LINK' => 'Users', 'NAME' => 'User', ], // ... ]; }
To fetch fields from a related table
$logs = \BlackFox\Log::I()->Select([ 'FIELDS' => [ 'ID', 'USER' => ['ID', 'LOGIN', 'EMAIL'], ], ]);
To filter the fields of the linked element
$logs = \BlackFox\Log::I()->Select([ 'FILTER' => [ 'USER.LOGIN' => 'Reuniko', ], ]);
One-to-many
The
You must specify the properties of the
-
LINK — the name of the SCRUD descendant class that describes the table that contains the reference field to the current table INNER_KEY — the field code in the external table that references the current table
Field of this type is virtual — it is not present in the database, but it can be selected and filtered
just like the
namespace BlackFox; class Users extends SCRUD { public $fields = [ 'ID' => self::ID, // ... 'GROUPS' => [ 'TYPE' => 'INNER', 'NAME' => 'Groups', 'LINK' => 'BlackFox\Users2Groups', 'INNER_KEY' => 'USER', ], ]; }
Many-to-many
In fact, a 'many-to-many' relationship is a combination of 'one-to-many' and 'many-to-one' relationships.
To create such a relationship, you must create a staging table that contains:
- master key (ID)
- reference to the first table (type
OUTER ) - reference to the second table (type
OUTER )
In the linked tables you must create virtual fields of type
namespace BlackFox; class Users2Groups extends SCRUD { public $fields = [ 'ID' => self::ID, 'USER' => [ 'TYPE' => 'OUTER', 'LINK' => 'Users', 'FOREIGN' => 'CASCADE', ], 'GROUP' => [ 'TYPE' => 'OUTER', 'LINK' => 'Groups', 'FOREIGN' => 'CASCADE', ], ]; }
Foreign keys
By default, the
To impose a constraint (foreign key) on a link, you must
add to the description of the field
Helper class Scheme will take care of checking the presence or absence of these restrictions in the database (as well as the structure of fields, primary keys and indexes) and will provide a sorted set of SQL strings to synchronize the database structure.
<?php
namespace BlackFox;
$Scheme = new Scheme([
User::I(),
Groups::I(),
Users2Groups::I(),
]);
$diffs = $Scheme->Compare();
foreach ($diffs as $diff)
Database::I()->Query($diff['SQL']);
// or:
$Scheme->Synchronize();