Stratadox/TableLoader

View on GitHub
src/Loader/Result.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php
declare(strict_types=1);

namespace Stratadox\TableLoader\Loader;

use ArrayIterator;
use BadMethodCallException;
use Exception;
use Stratadox\IdentityMap\IdentityMap;
use Stratadox\IdentityMap\MapsObjectsByIdentity;
use Traversable;

/**
 * Result.
 *
 * @author Stratadox
 */
final class Result implements ContainsResultingObjects
{
    private $objects;
    private $identityMap;

    private function __construct(
        array $objects,
        MapsObjectsByIdentity $identityMap
    ) {
        $this->objects = $objects;
        $this->identityMap = $identityMap;
    }

    /**
     * Makes a new result from an array of objects as produced by table loaders
     * and an identity map.
     *
     * @param array[]               $objects     Array of objects, as:
     *                                           [label => [id => object]]
     * @param MapsObjectsByIdentity $identityMap The map of objects by class and
     *                                           identifier.
     * @return ContainsResultingObjects
     */
    public static function fromArray(
        array $objects,
        MapsObjectsByIdentity $identityMap = null
    ): ContainsResultingObjects {
        return new self($objects, $identityMap ?: IdentityMap::startEmpty());
    }

    /** @inheritdoc */
    public function has(string $class, string $id): bool
    {
        return $this->identityMap->has($class, $id);
    }

    /** @inheritdoc */
    public function get(string $class, string $id): object
    {
        return $this->identityMap->get($class, $id);
    }

    /** @inheritdoc */
    public function add(
        string $label,
        string $idForLoading,
        string $idForMap,
        object $object
    ): ContainsResultingObjects {
        return new self($this->merge(
            $this->objects,
            [$label => [$idForLoading => $object]]
        ), $this->identityMap->add($idForMap, $object));
    }

    /** @inheritdoc */
    public function mergeWith(
        ContainsResultingObjects $otherObjects
    ): ContainsResultingObjects {
        return new self(
            $this->merge($this->objects, $otherObjects),
            $otherObjects->identityMap()
        );
    }

    /** @inheritdoc */
    public function include(
        string $label,
        string $id,
        object $object
    ): ContainsResultingObjects {
        return new self($this->merge(
            $this->objects,
            [$label => [$id => $object]]
        ), $this->identityMap);
    }

    /**
     * @param object[][] $result
     * @param object[][] $with
     * @return array
     */
    private function merge(array $result, iterable $with): array
    {
        foreach ($with as $label => $objects) {
            foreach ($objects as $id => $object) {
                $result[$label][$id] = $object;
            }
        }
        return $result;
    }

    /** @inheritdoc */
    public function identityMap(): MapsObjectsByIdentity
    {
        return $this->identityMap;
    }

    /** @inheritdoc */
    public function getIterator(): Traversable
    {
        return new ArrayIterator($this->objects);
    }

    /** @inheritdoc */
    public function offsetExists($offset): bool
    {
        return isset($this->objects[$offset]);
    }

    /** @inheritdoc */
    public function offsetGet($offset): array
    {
        return $this->objects[$offset];
    }

    /**
     * @inheritdoc
     * @throws Exception
     */
    public function offsetSet($offset, $value): void
    {
        throw new BadMethodCallException('Altering the results is not allowed.');
    }

    /**
     * @inheritdoc
     * @throws Exception
     */
    public function offsetUnset($offset): void
    {
        throw new BadMethodCallException('Altering the results is not allowed.');
    }
}