Jelle-S/TheSportsDb

View on GitHub
src/Entity/Proxy/Proxy.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php
/**
 * @file
 * Contains \TheSportsDb\Entity\Proxy\Proxy.
 */

namespace TheSportsDb\Entity\Proxy;

use TheSportsDb\Entity\EntityInterface;
use TheSportsDb\Entity\EntityManagerConsumerTrait;
use TheSportsDb\Entity\EntityManagerInterface;
use TheSportsDb\Entity\EntityPropertyUtil;
use TheSportsDb\Http\TheSportsDbClientInterface;

/**
 * Default implementation of proxy objects.
 *
 * @author Jelle Sebreghts
 */
abstract class Proxy implements ProxyInterface {

  use EntityManagerConsumerTrait;

  /**
   * The sports db client.
   *
   * @var \TheSportsDb\Http\TheSportsDbClientInterface
   */
  protected $sportsDbClient;

  /**
   * The already available properties.
   *
   * @var \stdClass
   */
  protected $properties;

  /**
   * The fully loaded entity object (lazy-loaded when needed).
   *
   * @var mixed
   */
  protected $entity;

  /**
   * {@inheritdoc}
   */
  public function __construct(\stdClass $values) {
    $this->properties = new \stdClass();
    $this->update($values);
  }

  /**
   * {@inheritdoc}
   */
  public function update(\stdClass $values) {
    if ($this->entity instanceof EntityInterface) {
      $this->entity->update($values);
      return;
    }
    foreach ((array) $values as $prop => $val) {
      if (method_exists($this, 'get' . ucfirst($prop))) {
        $this->properties->{$prop} = $val;
      }
    }
    if ($this->entityManager && $this->entityManager->isFullObject($this->properties, $this->getEntityType())) {
      $this->entity = $this->entityManager->factory($this->getEntityType())->create($this->properties, $this->getEntityType());
    }
  }

  /**
   * {@inheritdoc}
   */
  public function setEntityManager(EntityManagerInterface $entityManager) {
    $this->entityManager = $entityManager;
    // Check if we can create a full object once the entity manager is set.
    $stub = new \stdClass();
    $this->update($stub);
  }

  /**
   * {@inheritdoc}
   */
  public function setSportsDbClient(TheSportsDbClientInterface $sportsDbClient) {
    $this->sportsDbClient = $sportsDbClient;
  }

  /**
   * Gets a property, if it exists, loads it if necessary.
   *
   * @param string $name
   *   The property name.
   *
   * @return mixed
   *   The property value.
   */
  protected function get($name) {
    // If the full entity is loaded, use it.
    if ($this->entity instanceof EntityInterface) {
      return $this->entity->{'get' . ucfirst($name)}();
    }

    // If the property exists on the proxy, use it.
    if (property_exists($this->properties, $name)) {
      return $this->properties->{$name};
    }

    // The property does not exist on the proxy, and the entity is not loaded in
    // full yet, so load it first and repeat the operation.
    method_exists($this, 'load' . ucfirst($name)) ? $this->{'load' . ucfirst($name)}() : $this->load();
    return $this->get($name);

  }

  /**
   * {@inheritdoc}
   */
  abstract public function load();

  /**
   * {@inheritdoc}
   */
  public function raw() {
    if ($this->entity) {
      $this->_raw = $this->entity->raw();
      return $this->_raw;
    }
    if (!isset($this->_raw)) {
      $this->_raw = new \stdClass();
    }
    $reflection = new \ReflectionClass($this);
    $methods = $reflection->getMethods(\ReflectionMethod::IS_PUBLIC);
    foreach ($methods as $method) {
      $methodName = $method->getName();
      if (strpos($methodName, 'get') === 0) {
        $prop = lcfirst(substr($methodName, 3));
        if (isset($this->properties->{$prop}) && !property_exists($this->_raw, $prop)) {
          $this->_raw->{$prop} = NULL;
          $val = $this->{$methodName}();
          $this->_raw->{$prop} = EntityPropertyUtil::getRawValue($val);
        }
      }
    }
    return $this->_raw;
  }

  /**
   * {@inheritdoc}
   */
  public static function getEntityType() {
    $reflection = new \ReflectionClass(static::class);
    return strtolower(substr($reflection->getShortName(), 0, -5));
  }

  /**
   * {@inheritdoc}
   */
  public static function getPropertyMapDefinition() {
    $selfReflection = new \ReflectionClass(static::class);
    $namespace = substr($selfReflection->getNamespaceName(), 0, -5);
    $reflection = new \ReflectionClass($namespace . substr($selfReflection->getShortName(), 0, -5));
    return $reflection->getMethod('getPropertyMapDefinition')->invoke(NULL);
  }
}