octolab/Cleaner

View on GitHub
src/Util/WeightMatcher.php

Summary

Maintainability
A
30 mins
Test Coverage
<?php

namespace OctoLab\Cleaner\Util;

/**
 * @author Kamil Samigullin <kamil@samigullin.info>
 */
final class WeightMatcher implements MatcherInterface
{
    const BLANK = 0;
    const DENIAL = 1;
    const ENUM = 2;
    const ALL = 3;

    /** @var array */
    private $rules;

    /**
     * {@inheritdoc}
     */
    public function match($package, array $devFileGroups)
    {
        assert(is_string($package));
        $sortedRules = array();
        $packageNamespace = false !== ($pos = strpos($package, '/')) ? substr($package, 0, $pos) : '';
        if (isset($this->rules[$package])) {
            $sortedRules = $this->sort((array)$this->rules[$package]);
        } elseif ($packageNamespace && isset($this->rules[$packageNamespace.'/*'])) {
            $sortedRules = $this->sort((array)$this->rules[$packageNamespace.'/*']);
        } elseif (isset($this->rules['*'])) {
            $sortedRules = $this->sort((array)$this->rules['*']);
        }
        return array_values($this->apply($devFileGroups, $sortedRules));
    }

    /**
     * {@inheritdoc}
     */
    public function setRules(array $rules)
    {
        $this->rules = $rules;
        return $this;
    }

    /**
     * @param array $keys
     * @param array $rules
     *
     * @return array
     */
    private function apply(array $keys, array $rules)
    {
        $winner = array_filter($rules, function ($value) {
            return !empty($value);
        });
        reset($winner);
        $type = key($winner);
        $rule = current($winner);
        switch ($type) {
            case self::DENIAL:
                return array_filter($keys, function ($value) use ($rule) {
                    return $value !== $rule;
                });
            case self::ENUM:
                return array_intersect($keys, $rule);
            case self::ALL:
                return $keys;
            default:
                return array();
        }
    }

    /**
     * @param array $rules
     *
     * @return array
     *
     * @quality:method [B]
     */
    private function sort(array $rules)
    {
        $sorted = array(
            self::BLANK => $rules === array(),
            self::DENIAL => null,
            self::ENUM => array(),
            self::ALL => false,
        );
        foreach ($rules as $rule) {
            assert(is_string($rule));
            switch (true) {
                case $rule === '*':
                    $sorted[self::ALL] = true;
                    break 1;
                case $rule[0] === '!':
                    $sorted[self::DENIAL] = substr($rule, 1);
                    break 2;
                default:
                    $sorted[self::ENUM][] = $rule;
            }
        }
        return $sorted;
    }
}