Art4/json-api-client

Add a factory for class injection

Closed this issue · 0 comments

Art4 commented

Todo:

  • Create a factory
  • Create a manager who holds the factory
  • Provide the manager to __construct($object, $manager) in every object

tl;dr

The idea behind a factory is that the developer can override or inject every subclass to extend the library. A factory would be look like this:

<?php
namespace Art4\JsonApiClient\Utils;
class Factory
{
    /**
     * @var array
     */
    protected $specs = [
        'Document'            => 'Art4\JsonApiClient\Document',
        'Resource\Collection' => 'Art4\JsonApiClient\Resource\Collection',
        'Resource\Item'       => 'Art4\JsonApiClient\Resource\Item',
        // and so on...
    ];

    /**
     * @param array $overload Specs to be overloaded with custom classes.
     */
    public function __construct(array $overload = [])
    {
        if ($overload) {
            $this->specs = array_replace($this->specs, $overload);
        }
    }

    /**
     * Create a new instance of a class.
     * @param  string $spec
     * @param  array  $args
     * @return object
     */
    public function make($spec, array $args = [])
    {
        $class = new \ReflectionClass($this->specs[$spec])
        return $class->newInstanceArgs($args);
    }
}

We need a new class (eg. Manager) who inject the factory into every class.
This would change the way how a jsonapi_string will be parsed:

// create a factory if we want inject a class
$factory = new Art4\JsonApiClient\Utils\Factory([
    'Document' => 'My\Own\Document',
]);

// Set the factory into the manager
$manager = new Art4\JsonApiClient\Manager($factory);
// or 
$manager = new Art4\JsonApiClient\Manager();
$manager->setFactory($factory);

// Parse a jsonapi string
$document = $manager->parse($jsonapi_string); // $document will be My\Own\Document

As a last step the manager must provide into every class constructor so the class can use the factory. Injecting the manager instead of only the factory keeps us the ability to add more features in future without break BC (eg. config, parent_class, ...).

Example:

<?php

namespace Art4\JsonApiClient;

/**
 * Document Top Level Object
 *
 * @see http://jsonapi.org/format/#document-top-level
 */
class Document implements AccessInterface
{
    /**
     * @param object $object The document body
     * @param Manager $manager The manager
     *
     * @return Document
     *
     * @throws ValidationException
     */
    public function __construct($object, Manager $manager)
    {
        $this->manager = $manager;

        // ...

        if ( property_exists($object, 'jsonapi') )
        {
            // Use the factory to create the Jsonapi class
            $this->jsonapi = $this->manager->getFactory()->make('Jsonapi', [
                $object->jsonapi, 
                $this->manager, // don't forget to inject the manager
            ]);
        }

        // ...

        return $this;
    }
}