We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Transformers with Model, lazy-load problem

Currently I'm using this super nice tool to output API data https://fractal.thephpleague.com/transformers/#including-data

the problem is, does somebody has best case scenario on how to make it run Eager-Loading with Phalcon Model, are there any better alternative maybe?

edited Jul '16

Eager-loading is one of the worst patterns ever made. It's anti-pattern and you should never use it. Just use database joins. https://github.com/stibiumz/phalcon.eager-loading there is repo for eager-loading for phalcon but you should really avoid it.

... and what about Transformer?

edited Jul '16

What you mean abot transformer ? There is toArray() method which return mode las array already. What for exactly those transformers are ?

Pretty elegant library for casting an output

ex: https://fractal.thephpleague.com/simple-example/

Just not sure why you need it. You have toArray() method and setJsonContent in phalcon.

edited Jul '16

I need it, because

  • its pretty DRY
  • casting data types
  • very easy to change output data

this example is very messy, i need to write two times response output one for item, one for collection, looks pretty procedural also https://docs.phalcon.io/en/latest/reference/tutorial-rest.html#retrieving-data

with Transformer it's way more elegant

    class BookTransformer extends Fractal\TransformerAbstract
    {
        public function transform(Book $book)
        {
            return [
                'id'    => (int) $book->id,
                'title' => $book->title,
                'year'  => (int) $book->yr,
                'links' => [
                    [
                        'rel' => 'self',
                        'uri' => '/books/'.$book->id,
                    ],
                ],
            ];
        }
    }
edited Jul '16

No, you don't, you can just use instead of code in example:

 $robots = $app->modelsManager->executeQuery($phql);

    $data = array();
    foreach ($robots as $robot) {
        $data[] = array(
            'id'   => $robot->id,
            'name' => $robot->name
        );
    }

    echo json_encode($data);
$robots = $app->modelsManager->executeQuery($phql);
return $app->response->setJsonContent(['robots'=>$robots->toArray()]);

And select result from collection and use toArray() and setJsonContent too and it's basically it. No reason for adding additional classes, loading additional files, wasting memory resources etc when it's already built-in framework.

edited Jul '16

IMHO this is way more OOP way to do it

      class RobotTransformer extends Fractal\TransformerAbstract
      {
          /**
           * @param Robot $robot
           *
           * @return array
           */
          public function transform(Robot $robot)
          {
              return [
                  'id'    => (int) $robot->id,
                  'name' => $robot->title,
              ];

          }
      }

calling it, ex: item

       $robot = $app->modelsManager->executeQuery($phql); // imagine there is only one robot
       return $app->response->withItem($robot, new RobotTransformer);

calling it, ex: collection

       $robots = $app->modelsManager->executeQuery($phql);
       return $app->response->withCollection($robots, new RobotTransformer);
edited Jul '16

Then you can just do:

$robot = Robot::findFirst(1)->toArray(); // passing array toArray will simply get columns what you want, but you should just use parameters array in findFirst method and conditions
$robotCollection = RobotCollection::findFirst(1)->toArray();  // passing array toArray will simply get columns what you want, but you should just use parameters array in findFirst method and conditions

return $app->response->setJsonContent(['robot'=>$robot, 'robotCollection'=>$robotCollection]);

Just don't know why you need additional class for such simple stuff, when you can already achieve similar results. Also don't even know why you do things like this:

'id'    => (int) $robot->id

This looks ancient. Database driver should already return int, if mysql(mysqlnd) can return int then i guess other database systems can too.

I don't think that loading a Transformer is really a big memory waster, (I didn't do any tests, altought)

  • but using it's way more maintanable for changes(and modular) than manually adding to $data[] (that part looks pretty much like its 1995
edited Jul '16

But i just posted you better ways than doing data....

PHP is dynamically typed... not sure why would you want such a thing. Special cases would require additional logic either way

If you're working with APIs or even ajax responses, transformers are going to be your View in an MVC pattern. You can have UserAjaxTransformer or UserAPITransformer, with this your response structure will never be different in different endpoints. With Fractal, you'll also benefit from the standard json or xml responses, like structure of a single data, collection, pagination and other metas. Fractal is also compliant with jsonapi.org specs.