Deprecated I dropped this series like a year ago and have no plan on continuing. Read on if you like but don't expect much.

This is a part of series Datastore with PHP.

  1. Datastore with PHP - Part 1 - php-gds and datachore
  2. Datastore with PHP - Part 2 - Reinventing the wheel

In this series, I am going to wrap the php-gds to provide some functionalities and approaches of datachore in this library. (Part 1)

In this post, we will be building a class that:

  1. Is auto-mapped to the kind (category) in datastore based on the class name.
  2. Generate the schema with a declarative properties/fields list.

Since each instance of the class would have the same kind, schema and store, we can apply singleton pattern to store the results of the initial process as follow:

<?php
class Model {
  protected static $_store;
  protected static $_schema;
  protected static $_kind;

  public static function getStore() {
  	if ( !isset(static::$_store) ) {
      static::$_store = new GDS\Store(static::getSchema());
  	}
  	return static::$_store;
  }

  public static function getSchema() {
  	if ( !isset(static::$_schema) ) {
      static::$_schema = new GDS\Schema(static::getKind());
      //...
  	}
  	return static::$_schema;
  }

  public static function getKind() {
  	if ( !isset(static::$_kind) ) {
      // $classname = ...
  	}
  	return static::$_kind;
  }

However, it should be noticed that this pattern is not supposed to be used for this matter. If you inherit/extend the class all the new classes would be pointed to the same kind, schema and store. You would need to explicitly declare the protected static properties every single time:

<?php
class Test extends Model {
  protected static $_store;
  protected static $_schema;
  protected static $_kind;
  //...
}

Due to my limitation of php knowledge, I have yet to solve this problem yet. This is pending for an update from my future me :)


IMPORTANT: From here one, I would skip these declaration, but they are required if you would like to use my implementation without any modification of your own to fix it. If you have any idea how to fix it, please let me know. Thank you very much.


Getting the kind

Each Datastore entity is of a particular kind, which categorizes the entity for the purpose of queries: for instance, a task list application might represent each task to complete with an entity of kind Task. (Google)

We do this by invoking the method get_called_class() of php to retrieve the class name and create a schema with that name.

<?php
//...
$classname = get_called_class();
$schema    = new GDS\Schema($classname);
//...

However if you have a model class A in namespace B/C, the method get_called_class() would return B/C/A. This may fit with some people, but to simplify, I extract only the class name, without namespace, like so:

<?php
$classname = (substr($classname, strrpos($classname, '\\') + 1));

In full:

<?php
public static function getKind() {
  if ( !isset(static::$_kind) ) {
    $classname = get_called_class();
    static::$_kind = (substr($classname, strrpos($classname, '\\') + 1));
  }
  return static::$_kind;
}

Declarative schema definition

I take the syntax of datachore to implement my solution. A defined static property $properties, mapping a property name to a type, will be used to generate the schema. The static method getSchema() (see above) loops through $properties and applies appropriate method of GDS\Schema class.

To do this, we would need a class Type to declare all the types that we can handle, Here is a brief overview, the full code is not relevant and can be accessed at my gist:

<?php
class Type {
  const String     = 1;
  const Integer    = 2;
  const Datetime   = 3;
  const Float      = 4;
  const Boolean    = 5;
  const StringList = 6;
  const Geopoint   = 7;
  const Json       = 8;
  public static function setProperty($obj_schema, $property, $type, $index = FALSE) {
    switch ($type) {
      //...
    }
  }
}

For constants with values 1 to 7, these are the types that php-gds supports. The last constant, Json, is a new type that I would be handling in the upcoming post of this series, allowing us to save, read and update json fields in datastore.

The static method setProperty() takes 4 variables:

  1. $obj_schema - a GDS\Schema instance, the schema of a Model class.
  2. $property - the property name.
  3. $type - the type of the property.
  4. $index - a boolean value, indicating if the property should be indexed.

and run methods accordingly to complete the definition of $obj_schema.

A class extending Model should have a protected static property as follow:

<?php
protected static $properties = [
  "title"  => Type:String,
  "author" => Type:String,
  "isbn"   => [Type:String],
];

Here isbn field has a type of an array with only one element, which is Type:String, meaning isbn is a string and it should be indexed. This is just a way to declare and can be altered for a better implementation.

With Type class, we can now complete the getSchema() method of class Model by looping through static::$properties and run Type::setProperty() on each of the property:

<?php
public static function getSchema() {
  if ( !isset(static::$_schema) ) {
    static::$_schema = new GDS\Schema(static::getKind());
    foreach (static::$properties as $property => $type) {
      Type::setProperty(static::$_schema, $property, $type);
    }
  }
  return static::$_schema;
}

Next time on this series: implementing entity creation and access with Model constructor and php magic methods, along with proxying query access and performance from php-gds store and implementing Json field type. Stay tune and be awesome :)

Read other posts in series Datastore with PHP.

  1. Datastore with PHP - Part 1 - php-gds and datachore
  2. Datastore with PHP - Part 2 - Reinventing the wheel
Loading comments

netcell

Software engineer with 4+ years of work experience in designing and developing cross-platform games and apps on web technology.