Entities


Defining Entities


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>

Available attributes for entity element

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.

Using the entity with php


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);

Adding attributes


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)

phptype array

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) { ... }

  

phptype object

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>

Available attributes for the attribute element

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

Adding indexes


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>

Extending from Entities and Construct Factory


Extending from generated classes

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();
        }
}

Using a factory to instantiate

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,

Delimiting an entity


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,

In Memory replication with MySQL


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,