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

Google Cloud Datastore is a NoSQL document database built for automatic scaling, high performance, and ease of application development.(Google)

Google Cloud Datastore is a simple NoSQL service, and cheaper than SQL when using on Google Cloud, according to one of my friend. However, while he is running Java on Google App Engine, I am working on a PHP site and there are no official easy way to access this great solution yet.

Google Cloud Datastore is a great NoSQL solution (hosted, scalable, free up to a point), but it can be tricky (i.e. there’s lots of code glue needed) to get even the “Hello World” of data persistence up and running in PHP. (Tom Walder)

There are two popular PHP libraries available on Github that help us working with Datastore: php-gds by Tom Walder and datachore by Phillip Whelan. At the time of this post, php-gds is the one with most recent update, so I went with this library.

The setup

While the documentation of php-gds isn’t great, or rather lacking one, it is not hard to figure out how to use this library. To install over Composer, just include it in the field require in composer.json as follow:

{
    "require": {
        "tomwalder/php-gds": "v2.1.0"
    }
}

If you are running your app on App Engine, there are no setup needed, it’s plug-and-play. Otherwise, you would need to follow this guide for getting the JSON service key and this guide to configure the Google API Client, it’s not rocket science, but the guide is in need of upgrade for newbies.

The Ugly

While I prefer to use php-gds because its last update is more recent than datachore’s, I prefer the approach of datachore in term of schemas, entities creation and query. One way to describe the difference is that php-gds is a library (what you call), and datachore is a framework (what calls you) - not a correct comparison in this case, but you get the idea.

Here is a flow in php-gds:
  1. You create a schema - it’s not structured and can be messed up:
    <?php
    // Create a schema of kind 'Book' with 3 string fields
    $obj_schema = (new GDS\Schema('Book'))
    ->addString('title')
    ->addString('author', false)
    ->addString('isbn');
    
  2. Use that schema to build a store - it’s an unnecessary step and should be merged with schema:
    <?php
    // Build a store of that schema
    $obj_book_store = new GDS\Store($obj_schema);
    
  3. Run a method of that store to create an entity - where you can accidentally add a new, indexed field which would cost you and can be prevented in the schema definition step:
    <?php
    // Create an entity from that store
    $obj_book = $obj_book_store->createEntity([
     'title' => 'Some Book',
     'author' => 'A N Other Guy',
     'isbn' => '1840224313',
     'published' => new DateTime('-5 years')
    ]);
    
  4. Save that entity to the store - for some reason save/upsert and delete are not presented as a standalone section in the Getting started section of the php-gds github repository, but in the example and scattered around:
    <?php
    $obj_store->upsert($obj_book);
    
  5. Fetch from the store - why do I need to specify the kind name when I have already define it in the creation of the store?:
    <?php
    $query = "SELECT * FROM Book WHERE title = 'Some Book'";
    $obj_book_store->fetchOne($query);
    // or
    $obj_book_store->query($query);
    $obj_book_store->fetchOne()
    

Other tasks are shown in the php-gds github repository, I have not yet understood transaction and ancestry API so I would not discussed it in this series.


Now look at a flow in datachore:
  1. Creating schema, store in a single class definition:
    <?php
    namespace model;
    use \Datachore\Type;
    class Test extends \Datachore\Model {
     protected $properties = [
       "title"  => Type:String,
       "author" => Type:String,
       "isbn"   => Type:String,
     ];
    }
    
  2. Create an entity and save it directly (the same for deleting):
    <?php
    $test = new model\Test;
    $test->title     = 'Some Book';
    $test->author    = 'A N Other Guy';
    $test->isbn      = '1840224313';
    // Would not create a new indexed field
    $test->published = new DateTime('-5 years');
    $test->save();
    
  3. Query and find the entity - GQL query builder
    <?php
    $tests = model\Test::where('title', '=', 'Some Book')->get();
    

The approach of datachore is, in my opinion, much more elegant and simple to use. The library also supports more field types (including Set, similar to List type in Python version) and have a AutoIndexer to help ensuring we have an updated index.yaml which is required to use composite indexes on Google Cloud Datastore and avoid any missing index errors on the live system. However, I cannot find how to explicitly declare which field to index and which not to!


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. People normally say “don’t reinventing the wheel”, but I am doing this anyway due to these reasons:

  1. Reinventing the wheel is fun and I can learn a lot from it.
  2. The latest commit of datachore is on Dec 30, 2015 comparing to April 29, 2016 for php-gds’s.
  3. Lack of explicit index declaration in datachore?

Keep follow the path of this series below to accompany me on this journey of using Google Datastore with PHP.

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.