Using PHP Generators for Control Flow

As you may know from my last post covering Ember, I have become very interested in expanding my javascript skill set. I posted my 10 part Ember video series to /r/javascript and was glad to see it get some upvotes. I noticed a post about Koa.js sitting next to mine. Koa is touted as a next generation framework for node from the Express team. I have heard of Express but haven't done anything with it. Upon seeing there was something even newer, I was intrigued and decided to check it out.

What the heck is this voodoo?

I was really taken aback when I came to the Cascading section. The example showed a asterisk right in the middle of a closure definition and the use of a yield keyword.

// copy/pasted directly from Koa's docs
var koa = require('koa');
var app = koa();

// x-response-time
app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  this.set('X-Response-Time', ms + 'ms');
});

// logger
app.use(function *(next){
  var start = new Date;
  yield next;
  var ms = new Date - start;
  console.log('%s %s - %s', this.method, this.url, ms);
});

// response
app.use(function *(){
  this.body = 'Hello World';
});

app.listen(3000);


I had never seen that before. Upon some further investigation I learned that they are generators. Generators allow you to do some really crazy iterations. You can stop the iteration and give the calling code a value by using the yield keyword. You can also send the generator data back in the middle of an iteration. They're pretty mind bottling at first glance. I was curious to know if php has generators and guess what, they're new in 5.5!

I encourage you to get slightly familiar with them before reading on!

Anthony Ferrara has great article on generators here.

SitePoint also has a pretty good post about them here.

A Wikipedia article about generators.

Re-purposing generators

After I got a handle on what generators are I went back to the Koa website to review what they were doing. It didn't looking like they were using them for iteration though. It looks like they're using them to pass control to another generator, where execution halts in the first generator and continues in the next generator, which the first generator is completely unaware of. Once there are no more generators to continue on, flow unwinds back to the yield line in each generator. Koa's using them for a sort of cascading middleware. Look at Koa's docs if what I said didn't make any sense.

I found this concept to be incredibly clever and interesting. I wonder if I could implement the same idea in php...

Mental Gymnastics

This turned out to be a really fun challenge. Man...programming has really warped my idea of fun. Surprisingly, I was able to achieve the same effect. It took me a little while to figure it out and I didn't cheat and look at Koa's source! I'm not even sure with my javascript skills it would've helped much anyway.

Right this way

Let me show you an example.

$obj = new \stdClass;
$obj->result = '';

$first = function() use ($obj) {
    $obj->result .= ' 1 ';
    yield ControlFlow::NEXT;
    $obj->result .= ' 2 ';
};

$second = function() use ($obj){
    $obj->result .= ' 3 ';
    yield ControlFlow::NEXT;
    $obj->result .= ' 4 ';
};

$third = function() use ($obj){
    $obj->result .= ' 5 ';
    return ControlFlow::NEXT;
};

$fourth = function() use ($obj){
    $obj->result .= ' 6 ';
    return ControlFlow::NEXT;
};

$flow = new ControlFlow;
$flow->queue($first()) //notice the parenthesis for generators
     ->queue($second())
     ->queue($third)
     ->queue($fourth);

$flow->run();

echo trim($obj->result); // '1 3 5 6 4 2'

My ControlFlow object accepts two object types in the queue() method, \Generator's and \Closure's. It will always execute each queued action when the run() method is called but the order of execution is dependent on the contents of each generator/closure.

In the above example, the flow occurs like so:

  1. execution starts in the $first generator
  2. ' 1 ' is appended to $obj->result
  3. the $first generator then attempts to stop it's execution and yield/pass control to an unknown piece of code
  4. the ControlFlow then passes control to the next generator/closure which happens to be $second
  5. ' 3 ' is appended
  6. the $second generator then attempts to stop it's execution and yield/pass control to an unknown piece of code
  7. the ControlFlow then passes control to the next generator/closure which happens to be $third
  8. ' 5 ' is appended
  9. the ControlFlow then passes control to the next generator/closure which happens to be $fourth
  10. ' 6 ' is appended
  11. the ControlFlow attempts to pass control to the next generator/closure but none is found so it starts to unwind
  12. control is then relinquished back to the last yield, which is in $second
  13. ' 4 ' is appended
  14. control is then relinquished back to the previous yield, which is in $first
  15. ' 2 ' is appended
  16. '1 3 5 6 4 2' is echoed

If the $third closure did not return ControlFlow::NEXT, execution would have gone like this(the difference starts on step 9):

  1. execution starts in the $first generator
  2. ' 1 ' is appended
  3. the $first generator then attempts to stop it's execution and yield/pass control to an unknown piece of code
  4. the ControlFlow then passes control to the next generator/closure which happens to be $second
  5. ' 3 ' is appended
  6. the $second generator then attempts to stop it's execution and yield/pass control to an unknown piece of code
  7. the ControlFlow then passes control to the next generator/closure which happens to be $third
  8. ' 5 ' is appended
  9. $third doesn't direct flow to another piece of code, so it starts to unwind
  10. control is then relinquished back to the last yield, which is in $second
  11. ' 4 ' is appended
  12. control is then relinquished back to the previous yield, which is in $first
  13. ' 2 ' is appended
  14. control is then passed to the next action it hasn't executed yet, $fourth
  15. ' 6 ' is appended
  16. '1 3 5 4 2 6' is echoed

As you can see, each action will always be executed, but their order is entirely dependent on the contents of the actions.

It's worth mentioning, in the first scenario, that if there was a $fifth generator action that looked like the others(append ' 7 ' , yield next, append ' 8 '), both ' 7 ' and ' 8 ' would be appended at the same time because it would be the last action in the queue. It would then start to unwind.

I showed my coworker my example and he likened it to using templates, which is a great analogy. You have a template that has a placeholder for other markup to be rendered into. That base template has no idea what's going to get rendered into to but as soon as that happens it can continue on and render the rest of its own markup. I'm applying this same principle to php code.

Is this useful?

I have no idea! It's a pretty neat trick though. It seems like it could be a really confusing way to do some sort of pub/sub event propagation considering that generators are not required to yield anything. They must have the yield keyword in them but it could be wrapped up in a an if-statement that may not allow the execution to get there. Generators are strange beasts.

I would love to see someone smarter than me take this idea and run with it. I would be very curious to see what you come up with!

ControlFlow

Here's my ControlFlow class. It should probably be named something like YoYo.

class ControlFlow
{
    const NEXT = 'NEXT';
 
    /**
     * @var array
     */
    protected $queued = [];
 
    /**
     * @var array
     */
    protected $initiated = [];
 
    /**
     * Queue an action
     *
     * @param \Closure|\Generator $action
     * @return $this
     * @throws \InvalidArgumentException
     */
    public function queue($action)
    {
        if ( ! $action instanceof \Closure && ! $action instanceof \Generator) {
            throw new \InvalidArgumentException('Queued action must be a \Closure or \Generator');
        }
 
        $this->queued[] = $action;

        return $this;
    }
 
    /**
     * Run all queued actions
     *
     * @return void
     */
    public function run()
    {
        foreach ($this->queued as $action) {
            $this->runAction($action);
        }
 
        //flush everything because generators can't be reopened
        $this->flush();
    }
 
    /**
     * Run a queued action
     *
     * @param \Closure|\Generator $action
     * @return void
     */
    private function runAction($action)
    {
        if (in_array($action, $this->initiated, true)) return;
 
        $this->initiated[] = $action;
 
        if ($action instanceof \Generator) {
            $this->runGenerator($action);
        } elseif ($action instanceof \Closure) {
            $this->runClosure($action);
        }
    }
 
    /**
     * Run a queued closure
     *
     * @param \Closure $closure
     * @return void
     */
    private function runClosure(\Closure $closure)
    {
        if ($closure() === self::NEXT) {
            $this->initiateNext();
        }
    }
 
    /**
     * Run a queued generator
     *
     * @param \Generator $generator
     * @return void
     */
    private function runGenerator(\Generator $generator)
    {
        foreach ($generator as $result) {
            if ($result === self::NEXT) {
                $this->initiateNext();
            }
        }
    }
 
    /**
     * Initiate the next action
     *
     * @return void
     */
    private function initiateNext()
    {
        $nextAction = current($this->queued);
        next($this->queued);
        $this->runAction($nextAction);
    }
 
    /**
     * Remove the actions
     *
     * @return void
     */
    public function flush()
    {
        $this->queued = [];
        $this->initiated = [];
    }
}

Tags: PHP

Ember CRM

It's been a while since I last posted and for good reason...I've decided I need to attempt to compliment my backend skills with some frontend skills! I've never enjoyed writing javascript. Mostly because I've only ever used jQuery to added a little pizzazz to my sites(ie. toggleClass() and ajax()). I didn't have any javascript code organization. It was all spaghetti.

Javascript Revolution

Currently javascript is getting an insane amount of attention. New things are popping up all over the place(or maybe I've just been sheltered under my php rock). There are all sorts of frontend javascript frameworks now: Backbone, Angular, Ember, CanJS. Combine one of those with Twitter Boostrap or Zurb's Foundation and you can create some pretty slick frontends without doing much work.

Javascript is even becoming popular for the backend with the advent of Node. Node has spurred Express, Meteor, Sails, and more. I've got to say, programming both the backend and frontend with the same language is pretty darn appealing, even if I hate the fact that javascript isn't class based.

Where I'll start

Considering all that, I figure it would do my career well to really start giving javascript more of my attention. So where in the world do I start? Well, Ember seems to be the new hotness and even though I don't know a lick of ruby or rails, having a contributor to both rails and jQuery on the core team, gives me a warm fuzzy feeling. I'll start with Ember!

Ignition

After a couple of days of trying to create something I realized one thing: Ember is hard. Ember does a ton of magic for you behind the scenes. As a noob, this was a hindrance to me. I couldn't distinguish what Ember was doing for me and what it expected me to do. It was also extremely difficult to wrap my head around what MV* means in Ember. It doesn't resemble MVC in the backend at all. Once I realized and understood that, it all started to click and I've grown to really enjoy developing the frontend with Ember.

Another frustration of learning Ember/Ember-Data was the lack of up-to-date resources. I would constantly find stackoverflow questions that were "answered" and the answer referred to a jsfiddle that referenced "ember-latest.js" and guess what...Ember's api had changed, rendering it useless. So many times I found myself wanting to ditch it and stick to backend dev, but no, I don't want to be the guy unwilling to adapt. I. Must. Persevere.

I set out to build a tiny CRM application and implement some features I know I'll run into when developing something for real. Some features like:

  • basic CRUD operations
  • various relationship types, including a polymorphic relationship
  • loading relationships asynchronously
  • modals
  • Select2 integration
  • data normalization, serialization
  • and more
After trying to soak up absolutely everything Ember(stackoverflow, blogs, digging through the docs, IRC) for a solid two weeks I finally found some enlightenment. I successfully built out my application and am delighted with the result.

I've recorded a 10 part video playlist of myself rebuilding the app so that you all may reap the benefits of my efforts. I know when I first set out to learn ember I got tired of being pointed to paid methods of learning the framework. This is me giving back for all of the help I've received on my quest. Enjoy.

Project Overview

Before we get started I think it makes the most sense to have a look at what we're going to build.


You can find all of the frontend source code in the repo. Each part has its own branch.

Part 1

Let's get to it. In this first episode we're going to cover:

  • project structure
  • libraries used
  • model definitions
  • route definitions


Part 2

Topics covered:

  • creating Route objects
  • retrieving models from the ember-data store/API
  • expected JSON format
  • displaying a list of models in a template
  • using a few handlebars helpers


Part 3

Topics covered:

  • creating a route that uses a dynamic segment
  • using handlebars partials
  • getting and displaying related models
  • sending actions from templates to controllers
  • using ember-data model flags
  • rolling back model changes
  • saving models


Part 4

Topics covered:

  • reviewing relationship JSON
  • creating a custom REST serializer


Part 5

Topics covered:

  • creating a route for new models
  • rendering a specific template from the route
  • what JSON to return when saving models
  • removing unused models
  • cleaning up unsaved model changes


Part 6

Topics covered:

  • hiding models based on properties
  • creating mixins for our controllers
  • handling backend errors
  • using Twitter Bootstrap's alerts


Part 7

Topics covered:

  • fixing a mixin bug
  • reviewing my error response JSON


Part 8

Topics covered:

  • implementing everything we've done for companies so far for people


Part 9

Topics covered:

  • fixing a dynamic model property bug
  • incorporating Select2 using a custom view
  • using meta data in our JSON
  • sending actions from a view


Part 10

Topics covered:


<

p>

Questions, comments?

I hope you've found this useful. It was a really fun exercise and it sparked my interest to dive deeper into the javsacript world.

I'd love to hear any questions or comments. As I said in the first video, I want to learn from you guys as well. Please tell me if I'm doing something wrong or I could be doing something better!

Help! One huge aspect I didn't touch on was pagination. I'm still lurking and trying to figure out the best way to handle it. I'd love to learn more about the preferred method of paginating requested models using the meta object, especially paginating related models. For instance, if I'm on the company route, viewing a company that has 10,000 tasks, how do you paginate through those?

If you have some ideas, please let me know! I'll append this post with the information.

Tags: Javascript, Ember, Ember-data

Eloquent and SQL Views

I'm currently on a mission to learn ember.js. This is my first attempt at frontend development and ember seems to be the new hotness so I figured I'd give it a shot. I'm building the backend api with Laravel. Out of the box, Laravel is pretty well-suited for building an api. However, after learning what json responses ember expects, I realized there was some work to be done.

The dilemma

I was reading through the ember rest adapter guide and came across the model relationship expectations. Ember expects something like the following.

{
    "company": {
        "id": 1,
        "name": "Acme Company",
        "person_ids": [1, 2, 3]
    }
}


Notice how the relationship ids are contained in an array. Ember does support sideloading models like below.

{
    "company": {
        "id": 1,
        "name": "Acme Company",
        "person_ids": [1, 2, 3],
        "people": [{
            "id": 1,
            "name": "David Adams"
        },
        {
            "id": 2,
            "name": "John Doe"
        },
        {
            "id": 3,
            "name": "Bob Smith"
        }]
    }
}


The problem with this is that if your app is of any size, this isn't an option. Too much data would be loaded.

Laravel is awesome in that you can side/eager load models but there isn't an option for eager loading data outside of entire models. For example, the person_ids in our company models.

My first attempt

The very last section in the eloquent docs informs us that we can define custom accessors that don't have a corresponding column in the database. I thought I would use this feature to accomplish my goal.

class Company extends \Eloquent
{
    protected $table = 'companies';

    protected $appends = ['person_ids'];

    protected $person_ids;

    public function people()
    {
        return $this->hasMany('Person');
    }

    public function getPersonIdsAttribute()
    {
        if (is_null($this->person_ids)) {
            $ids = DB::table('people')->where('company_id', '=', $this->id)->lists('id');

            $this->person_ids = array_map('intval', $ids);
        }

        return $this->person_ids;
    }
}


This accomplishes my goal....but there is one big problem. This solution has the N + 1 query problem. I'm adding a lot of database overhead with this approach. Every model retrieved will require one more query to get all of its data. This isn't optimal at all.

The solution

Rather than require a separate query made by php, it would be better to have sql handle that for us behind the scenes. It would be great to be able to use a sql view to read the data from instead of directly off of the table.

Fact! A sql view is basically a predefined query that is treated like table to read data from. You can create a view from a complex select statement that joins multiple tables and colums from different tables. Once created, you can select from the view, SELECT * FROM your_view_name.

I created a view with the following migration.

class CreateCompaniesView extends Migration 
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        DB::statement("CREATE VIEW companiesView AS
                        SELECT *,
                        (
                            SELECT GROUP_CONCAT(DISTINCT id SEPARATOR ',')
                            FROM people AS p
                            WHERE p.company_id = c.id
                        ) AS person_ids
                        FROM companies AS c");
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        DB::statement("DROP VIEW companiesView");
    }
}


This allows me to issue a query like SELECT * FROM companiesView and get the following resultset:

id created_at updated_at name person_ids
1 2013-11-10 06:29:48 2013-11-10 06:29:48 Acme Company 3,4
2 2013-11-10 06:29:48 2013-11-10 06:29:48 FooBar Industries 2,8,12

Now we need to figure out how to incorporate this view into our eloquent model.

Eloquent and views

We can't simply change the $table property on our model to the newly created view. Views cannot be written to, only read from. We need to provide the writable $table along with a $readFrom property where we can specify a view.

My first thought was to hook into the saving and saved eloquent model events to swap out the view for the real table when saving. I learned that the saving event isn't fired soon enough though. Eloquent has already built part of the query at that point.

Rather than using events, I decided to wrap eloquent with my own BaseModel class. This allows me to override the save() method and juggle the table/view before and after the actual save.

public function save(array $options = [])
{
    $this->toWriteMode();

    try {
        $saved = parent::save($options);
    } catch (\Exception $e) {
        $this->toReadMode();
        throw $e;
    }

    $this->toReadMode();

    return $saved;
}


The toWriteMode() and toReadMode() methods simply swap the $table to the appropriate table or view.

Read only attributes

The next problem is figuring out how to handle these read only attributes, ie. person_ids. These values need to be attributes on the models but not saved to the database.

We need a way to cache these read only values, remove them from being attributes on the model, save the model, and then add them back after the model is saved.

//part of the BaseModel class

    protected $readOnly = [];

    protected $readOnlyCache = [];

    public function save(array $options = [])
    {
        $this->toWriteMode();
        $this->cacheReadOnly();

        try {
            $saved = parent::save($options);
        } catch (\Exception $e) {
            $this->toReadMode();
            throw $e;
        }

        $this->toReadMode();
        $this->restoreReadOnly();

        return $saved;
    }

    protected function cacheReadOnly()
    {
        $this->readOnlyCache = [];

        foreach ($this->readOnly as $key) {
            $value = $this->getAttributeValue($key);
            $this->readOnlyCache[$key] = $value;
            $this->__unset($key);
        }
    }

    protected function restoreReadOnly()
    {
        foreach ($this->readOnlyCache as $key => $value) {
            $this->setAttribute($key, $value);
        }
    }


Sweet. Now in our model classes, we just need to provide an array of $readOnly attributes.

Putting it all together

With the creation of this base model class we can define a company model like below.

class Company extends BaseModel
{
    protected $table = 'companies';

    protected $fillable = ['name'];

    protected $guarded = ['id'];

    public function people()
    {
        return $this->hasMany('Person');
    }
} 


There's absolutely nothing new in this Company class. It works just as you would expect. However, now we can extend this class to create an EagerCompany class.

class EagerCompany extends Company
{
    protected $readFrom = 'companiesView';

    protected $readOnly = ['person_ids'];

    public function getPersonIdsAttribute($ids)
    {
        return $this->intArrayAttribute($ids);
    }
} 


This class will read its data from the view we created earlier and we can save and retrieve it as normal. It will fetch our read only attributes and they will be handled appropriately when saving.

That new intArrayAttribute() method just converts the comma delimited id string returned from the view into an array of integers.

We have some options now. We can use the Company internally but if we need those extra read only attributes, say in an api response, we can use the EagerCompany class.

I found this to work quite well for getting a list of ids for relationships. I also plan to use this same idea for returning counts of relationships.

{
    "company": {
        "id": 1,
        "name": "Acme Company",
        "person_ids": [1, 2, 3],
        "people_count": 3
    }
}


The base model

I've only shown you bits and pieces of this base model up until now. Here's the whole enchilada.

/**
 * Base model for allowing reads from sql views
 *
 * Class BaseModel
 * @package ProgrammingAreHard\Models
 */
abstract class BaseModel extends \Eloquent
{
    /**
     * Writable table
     *
     * @var string
     */
    protected $writeTable;

    /**
     * Read table/view
     *
     * @var string
     */
    protected $readFrom;

    /**
     * Read only attributes (not to be saved)
     *
     * @var array
     */
    protected $readOnly = [];

    /**
     * Cache for read only attribute values
     *
     * @var array
     */
    protected $readOnlyCache = [];

    /**
     * Instantiate and set the table
     *
     * @param array $attributes
     */
    public function __construct(array $attributes = [])
    {
        parent::__construct($attributes);

        $this->writeTable = $this->getTable();

        $this->toReadMode();
    }

    /**
     * Juggle the table and read only attributes
     *
     * @param array $options
     * @return bool
     * @throws \Exception
     */
    public function save(array $options = [])
    {
        $this->toWriteMode();
        $this->cacheReadOnly();

        try {
            $saved = parent::save($options);
        } catch (\Exception $e) {
            $this->toReadMode();
            throw $e;
        }

        $this->toReadMode();
        $this->restoreReadOnly();

        return $saved;
    }

    /**
     * Cache and remove read only attributes
     *
     * @return void
     */
    protected function cacheReadOnly()
    {
        $this->readOnlyCache = [];

        foreach ($this->readOnly as $key) {
            $value = $this->getAttributeValue($key);
            $this->readOnlyCache[$key] = $value;
            $this->__unset($key);
        }
    }

    /**
     * Restore the cached read only attributes
     *
     * @return void
     */
    protected function restoreReadOnly()
    {
        foreach ($this->readOnlyCache as $key => $value) {
            $this->setAttribute($key, $value);
        }
    }

    /**
     * Get the writable table
     *
     * @return string
     */
    public function getWriteTable()
    {
        return $this->writeTable;
    }

    /**
     * Swap to the writable table
     *
     * @return void
     */
    protected function toWriteMode()
    {
        $this->setTable($this->getWriteTable());
    }

    /**
     * Get the readable table/view
     *
     * @return string
     * @throws \Exception
     */
    public function getReadFrom()
    {
        if (is_null($this->readFrom)) {
            $this->readFrom = $this->getWriteTable();
        }

        return $this->readFrom;
    }

    /**
     * Swap to the readable table/view
     *
     * @return void
     */
    protected function toReadMode()
    {
        $this->setTable($this->getReadFrom());
    }

    /**
     * Convert the value to an int array if needed
     *
     * @param string|array $value
     * @return array
     */
    protected function intArrayAttribute($value)
    {
        if (is_string($value) and strlen($value) > 0) {
            $value = explode(',', $value);
            $value = array_map('intval', $value);
        }

        return is_array($value) ? $value : [];
    }
}


The controller

Here's a very simplified version of my controller.

class CompaniesController extends \BaseController 
{
    /**
    * Display a listing of companies.
    *
    * @return Response
    */
    public function index()
    {
        $res = new stdClass;
        $res->companies = EagerCompany::all()->toArray();

        return Response::json($res);
    }

    /**
    * Display a single company.
    *
    * @param  int  $id
    * @return Response
    */
    public function show($id)
    {
        $res = new stdClass;
        $res->company = EagerCompany::find($id)->toArray();

        return Response::json($res);
    }
}


I feel like this is a pretty good way to handle eager loading of non-model data. Maybe there's a better way to do this. I'd love to hear any ideas if you have some!

Tags: PHP, Intermediate, Laravel