An entity always represents on table in the database. This will result in a generated class that provides functionality for loading and storing the entity in the database table defined Sample of Entity. Database specific information can be defined in the entity-mysql element.
<?xml version="1.0" encoding="UTF-8"?> <entityList> <entity name="Artist" namespace="siestaphp\tests\gen" targetPath="gen/"> <entity-mysql charset="utf8" collate="utf8_general_ci" engine="MEMORY"/> <attribute name="id" type="int" dbType="INT" primaryKey="true" required="true" autoValue="autoincrement"/> <attribute name="bool" type="bool" dbType="SMALLINT"/> <attribute name="int" type="int" dbType="INT"/> <attribute name="float" type="float" dbType="FLOAT"/> <attribute name="string" type="string" dbType="VARCHAR(100)"/> </entity> </entityList>
Name | Required | default | allowed values | description |
name | yes | valid php class names | Name of the class that is generated | |
namespace | no | valid php namespace | Namespace of the class to generate | |
table | no | name of the class | valid database table names | Name of the database table |
targetPath | no | . | valid path (does not need to exist) | By default the path is calculated psr-0 compliant. By setting a targetPath you overwrite this behaviour |
delimit | no | false |
true|false |
Allows to track history of the table |
replication | no | false |
true|false |
Table will be created twice. |
An object can be instantiated with the classname respectively the construct classname. Static methods allow to find or delete entities by primary key.
// create new instance, set value and save $artist = new Artist(); $artist->setName("Kruder & Dorfmeister"); $artist->save(); // you can initialize the object from a json object $artist->fromJSON($jsonString); // you can also transform the object to json $jsonString = $artist->toJSON(); // you can also initialize an object from an array or transfer it to an array $artist->fromArray($arrayData); $arrayData = $artist->toArray(); // finding an entity by primary key $service = ArtistService::getInstance(); $artist2 = $service->getEntityByPrimaryKey(4); // deleting an entity by primary key $service->deleteEntityByPrimaryKey(4);
For every attribute defined in the XML there will be a member in the class and a column in the table. An entity can have several primary key columns. The following methods will be generated for every attribute.
/** * @return string|null */ public function getName() { ... } /** * @param string $value * * @return void */ public function setName(string $value = null) { ... }
Getters for primary key attributes have additional flags to trigger the generation of IDs.
If $generateKey
is set to true, you can force the generation of a new Id.
Furthermore a $connectionName
can be specified which configured connection should be used.
/** * @param bool $generateKey * @param string $connectionName * * @return int|null */ public function getId(bool $generateKey = false, string $connectionName = null)
Siesta allows to define the type array
. Therefore an array will be created to store
any information in. When the attribute is saved the content will be persisted as a json
string. You should use a database type that fits the desired length (TEXT e.g.)
<entity name="Album" namespace="Siesta\Tests\Entity"> <attribute name="id" type="int" dbType="INT" primaryKey="true" autoValue="autoincrement"/> <attribute name="attributeList" type="array" dbType="TEXT"/> </entity>
Besides the standard getter and setter the following additional method are generated for a 'array' attribute.
/** * @param string $key * @param $value * * @return void */ public function addToAttributeList(string $key, $value = null) { ... } /** * @param string $key * * @return mixed */ public function getFromAttributeList(string $key) { ... }
Siesta allows to a custom class as member. The object if not null, will be serialized when persisting
and deserialized when reading from the database. If you want to have the object be included when
transforming the entity toArray()
or toJSON()
your objects needs to implement
the interface Siesta\Contract\ArraySerializable
<entity name="Album" namespace="Siesta\Tests\Entity"> <attribute name="id" type="int" dbType="INT" primaryKey="true" autoValue="autoincrement"/> <attribute name="myObject" type="SiestaTest\End2End\Util\AttributeSerialize" dbType="TEXT"/> </entity>
Name | Required | default | allowed values | description |
name | yes | allowed php variable names | Name of the attribute that is generated | |
type | yes | bool|int|float|string|SiestaDateTime|array|{existingClass} |
defines the php type to use for the attribute | |
dbName | no | defined NamingStrategy will determine db name | allowed database column names | name of the column in the database |
dbType | yes | INT, VARCHAR, BLOB etc. |
database type for the column to use | |
transient | no | false | true|false |
allows to define attributes that are not stored in the database |
primaryKey | no | false | true|false |
allows to define a primarykey |
defaultValue | no | null | valid php code : 'abc', 123 or new SiestaDateTime() |
the default value to use for the attribute |
required | no | false | true|false |
creates a not null constraint for the table |
autoValue | required for primary key columns | uuid|autoincrement|{your custom sequencer} | defines how the primary key column is set |
You can configure indexes within the entity.xml file. Every index needs a name. The unique flag
can be true|false
and decides if the index is supposed to be unique. An index
consists of at least one indexPart which defines on which column the index is to be build.
<?xml version="1.0" encoding="UTF-8"?> <entityList> <entity name="ArtistEntity" namespace="siestaphp\tests\functional\index\gen" targetPath="gen/"> <attribute name="string" type="string" dbType="VARCHAR(100)"/> <attribute name="string2" type="string" dbType="VARCHAR(100)"/> <index name="uniqueIndex" unique="true" type="btree"> <indexPart attributeName="string" sortOrder="ASC" length="10"/> <indexPart attributeName="string2" sortOrder="ASC" length=""/> </index> <index name="nonUniqueIndex" unique="false" type="hash"> <indexPart attributeName="string2" sortOrder="ASC" length="20"/> </index> </entity> </entityList>
Typically you want to extend from the generated entity to add your custom coding. To make sure Siesta instantiates the right class, you can add a constructor element and define the derived class. Make sure the class extends from the generated entity
<entity name="FestivalEntity" namespace="SiestaTest\End2End\Construct\Generated" table="festival_entity" > <constructor className="SiestaTest\End2End\Construct\Entity\Festival"/> <attribute name="id" type="int" dbType="INT" primaryKey="true" required="true" autoValue="autoincrement"/> </entity>
Your custom class would look like this
namespace SiestaTest\End2End\Construct\Entity; use SiestaTest\End2End\Construct\Generated\FestivalEntity; class Festival extends FestivalEntity { public function __construct() { // make sure to invoke parent constructor parent::__construct(); } }
If you have a central factory in place that does instantiation and or dependency injection you can define a factory method to invoke to obtain a new instance. This is done with the constructCall attribute. Furthermore the constructFactoryClassName is needed to include a use statement. Instantiation of new objects will be done by invoking the defined method.
<entity name="CustomerEntity" namespace="SiestaTest\End2End\Construct\Generated" table="customer" > <constructor className="SiestaTest\End2End\Construct\Entity\Customer" constructCall="CustomerFactory::newCustomerEntity()" constructFactoryClassName="SiestaTest\End2End\Construct\Entity\CustomerFactory"/> <attribute name="id1" type="int" dbType="INT" primaryKey="true" required="true" autoValue="autoincrement"/> </entity>
Example
Construct Test,
Construct Schema,
Sometimes it is useful to archive changes that have been made to an entity. Siesta allows
to automatically generate an archive table which will store changes over time.
Use the attribute delimit="true"
to enable the feature
for a specific table.
mysql> show columns from Artist; +-------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+-------+ | id | int(11) | NO | PRI | NULL | | | name | varchar(100) | YES | | NULL | | | city | varchar(100) | YES | | NULL | | +-------+--------------+------+-----+---------+-------+
With the delimit flag set to true, Siesta will generate a second table:
mysql> show columns from Artist_delimit; +-------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------------+--------------+------+-----+---------+-------+ | _delimitId | varchar(36) | NO | PRI | | | | _validFrom | datetime | YES | | NULL | | | _validUntil | datetime | YES | | NULL | | | id | int(11) | NO | | NULL | | | name | varchar(100) | YES | | NULL | | | city | varchar(100) | YES | | NULL | | +-------------+--------------+------+-----+---------+-------+
The delimiter table contains the same columns like the original table (id, name, city).
Furthermore it comes with a a _delimit_id, _validFrom and _validUntil column.
The following example shows how they are used
mysql> select * from artist; +----+-----------+--------+ | id | name | city | +----+-----------+--------+ | 1 | MC Hammer | London | +----+-----------+--------+ mysql> select * from artist_delimit; +-------------+---------------------+---------------------+----+-----------+--------+ | _delimit_id | _validFrom | _validUntil | id | name | city | +-------------+---------------------+---------------------+----+-----------+--------+ | 68f04490 | 1988-10-24 18:58:12 | NULL | 1 | MC Hammer | London | +-------------+---------------------+---------------------+----+-----------+--------+
When the artist is initially created the delimiting table contains the entire record with a _validFrom data and null for the _validUntil field, which indicates that this is the currently valid record. Let's rename the artist to 'Hammer' and see what is happening.
// finding an entity by primary key $hammer = Artist::getEntityByPrimaryKey(1); // rename $hammer->setName("Hammer"); // save again $hammer->save();
This will result in the following table contents.
mysql> select * from artist; +----+-----------+--------+ | id | name | city | +----+-----------+--------+ | 1 | MC Hammer | London | +----+-----------+--------+ mysql> select * from artist_delimit; +-------------+---------------------+---------------------+----+-----------+--------+ | _delimit_id | _validFrom | _validUntil | id | name | city | +-------------+---------------------+---------------------+----+-----------+--------+ | 68f04490 | 1988-10-24 18:58:12 | 1992-10-24 18:58:12 | 1 | MC Hammer | London | | 68f09bd4 | 1992-10-24 18:58:12 | NULL | 1 | Hammer | NY | +-------------+---------------------+---------------------+----+-----------+--------+
The delimiting table contains 2 rows. The first one still shows the name 'MC Hammer' but with a VALID_UNTIL date
set. The second entry shows the new name 'Hammer' with a VALID_FROM date and NULL for the VALID_UNTIL (which
indicates this is the currently active record). Both entries refer to the same id 1 refering to the
id from the artist table. If you delete the entity the valid until data will be set to the time of deletion
Example
Delimit Test,
Delimit Schema,
MySQL allows to create tables with the Memory engine. The Memory engine is stored in the memory rather than on hard disk. Siesta allows to replicate a table with the memory engine. The same table will be present with configured engine and with the memory engine.
mysql> show tables from SIESTA_TEST; +-----------------------+ | Tables_in_siesta_test | +-----------------------+ | Book | | Book_MEMORY | +-----------------------+
Every save operation will result in INSERT/UPDATE statement for both tables. However SELECT statement are working on the memory
table only. The following shows the insert procedure which is invoked on $book->save();
It updates both the memory
table as well as the persistence table.
# stored procedure to Insert a book CREATE PROCEDURE `Book_I` (IN P_id VARCHAR(36),IN P_title VARCHAR(100),IN P_price FLOAT) MODIFIES SQL DATA SQL SECURITY INVOKER BEGIN INSERT INTO `Book` ( `id`,`title`,`price` ) VALUES ( P_id,P_title,P_price ); INSERT INTO `Book_MEMORY` ( `id`,`title`,`price` ) VALUES ( P_id,P_title,P_price ); END #stored procedure to find by primary key CREATE PROCEDURE `Book_FBPK`(IN P_id VARCHAR(36)) READS SQL DATA SQL SECURITY INVOKER BEGIN SELECT * FROM `Book_MEMORY` WHERE `id` = P_id; END
Important: As of now TEXT and BLOB column types are not allowed for memory engines in mysql.
Example
Replication Test,
Replication Schema,