AthensFramework/core

View on GitHub
src/filter/RelationFilter.php

Summary

Maintainability
D
1 day
Test Coverage
<?php

namespace Athens\Core\Filter;

use Athens\Core\ORMWrapper\ObjectWrapperInterface;
use Exception;

use Athens\Core\ORMWrapper\QueryWrapperInterface;
use Athens\Core\Row\RowInterface;

/**
 * Class RelationFilter
 *
 * @package Athens\Core\Filter
 */
class RelationFilter extends SelectFilter
{

    const ALL = 'All';
    const ANY = 'Any';
    const NONE = 'None';

    /** @var ObjectWrapperInterface[] */
    protected $relations = [];

    /** @var string */
    protected $relationName = '';

    /** @var string */
    protected $relationNamePlural = '';

    /**
     * @param string                $id
     * @param string[]              $classes
     * @param string[]              $data
     * @param QueryWrapperInterface $query
     * @param mixed                 $default
     * @param FilterInterface|null  $nextFilter
     */
    public function __construct(
        $id,
        array $classes,
        array $data,
        QueryWrapperInterface $query,
        $default,
        FilterInterface $nextFilter = null
    ) {
        $this->relationName = array_slice(explode('\\', $query->getPascalCasedObjectName()), -1)[0];

        $this->relationNamePlural = $this->relationName . (substr($this->relationName, -1) === 's' ?  'es' : 's');

        $relations = $query->find();

        $relationOptions = [];
        foreach ($relations as $relation) {
            $key = $this->makeRelationKey($relation);
            $relationName = (string)$relation;

            $this->relations[$key] = $relation;
            $relationOptions[$key] = $relationName;
        }

        if ($default === static::ALL) {
            $default = $this->getAllText();
        } elseif ($default === static::ANY) {
            $default = $this->getAnyText();
        } elseif ($default === static::NONE) {
            $default = $this->getNoneText();
        }

        $this->options = array_merge(
            [$default, ''],
            $relationOptions,
            [$this->getAllText(), $this->getAnyText(), $this->getNoneText()]
        );

        if ($nextFilter === null) {
            $this->nextFilter = new DummyFilter();
        } else {
            $this->nextFilter = $nextFilter;
        }

        $this->id = $id;
        $this->statements = [];
        $this->classes = $classes;
        $this->data = $data;
    }

    /**
     * @param ObjectWrapperInterface $relation
     * @return string
     */
    protected function makeRelationKey(ObjectWrapperInterface $relation)
    {
        return base64_encode((string)$relation->getPrimaryKey());
    }

    /**
     * @return string
     */
    public function getAllText()
    {
        return "All ({$this->relationNamePlural})";
    }

    /**
     * @return string
     */
    public function getAnyText()
    {
        return "Having Any {$this->relationName}";
    }

    /**
     * @return string
     */
    public function getNoneText()
    {
        return "Having No {$this->relationName}";
    }

    /**
     * @param QueryWrapperInterface $query
     * @return QueryWrapperInterface
     * @throws \Exception if given an incompatible query type.
     */
    public function queryFilter(QueryWrapperInterface $query)
    {
        $this->canQueryFilter = true;
        if ($this->getNextFilter()->canQueryFilter === false) {
            $this->canQueryFilter = false;
        }

        if ($this->canQueryFilter === true) {
            $query = $this->getNextFilter()->queryFilter($query);
            $choiceKey = FilterControls::getControl($this->id, "value", array_keys($this->options)[0]);

            $choice = $this->options[$choiceKey];
            $fieldName = array_search("{$this->relationName}Id", $query->getUnqualifiedPascalCasedColumnNames());

            switch ($choice) {
                case $this->getAllText():
                    break;
                case $this->getAnyText():
                    $query = $query->filterBy(
                        $fieldName,
                        null,
                        QueryWrapperInterface::CONDITION_NOT_EQUAL
                    );
                    break;
                case $this->getNoneText():
                    $query = $query->filterBy(
                        $fieldName,
                        null,
                        QueryWrapperInterface::CONDITION_EQUAL
                    );
                    break;
                default:
                    $relation = $choice;
                    if (is_string($relation) === true) {
                        $relation = $this->relations[array_search($relation, $this->options)];
                    }

                    $query = $query->filterBy(
                        $fieldName,
                        $relation->getPrimaryKey(),
                        QueryWrapperInterface::CONDITION_EQUAL
                    );
                    break;
            }
        }

        return $query;
    }

    /**
     * @param RowInterface[] $rows
     * @return RowInterface[]
     */
    public function rowFilter(array $rows)
    {
        return $rows;
    }
}