Completed
Push — master ( 0ca994...bcdd07 )
by Neomerx
05:23
created

FluteSettings::createModelToSchemeMap()   C

Complexity

Conditions 7
Paths 2

Size

Total Lines 32
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 32
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 18
nc 2
nop 0
1
<?php namespace Limoncello\Flute\Package;
2
3
use Generator;
4
use Limoncello\Contracts\Settings\SettingsInterface;
5
use Limoncello\Flute\Contracts\Schema\SchemaInterface;
6
use Limoncello\Flute\Contracts\Validation\JsonApiRuleSetInterface;
7
use Limoncello\Flute\Validation\Execution\JsonApiRuleSerializer;
8
9
/**
10
 * @package Limoncello\Flute
11
 */
12
abstract class FluteSettings implements SettingsInterface
13
{
14
    /**
15
     * By default it checks that all Schemes have unique resource types. That's a legit case
16
     * to have multiple Schemes for a same resource type however it's more likely that developer
17
     * just forgot to set a unique one. If you do need multiple Schemes for a resource feel free
18
     * to set it to `false`.
19
     *
20
     * @var bool
21
     */
22
    protected $requireUniqueTypes = true;
23
24
    /**
25
     * @return string
26
     */
27
    abstract protected function getSchemesPath(): string;
28
29
    /**
30
     * @return string
31
     */
32
    abstract protected function getRuleSetsPath(): string;
33
34
    /**
35
     * @param string $path
36
     * @param string $implementClassName
37
     *
38
     * @return Generator
39
     */
40
    abstract protected function selectClasses(string $path, string $implementClassName): Generator;
41
42
    /** Config key */
43
    const KEY_MODEL_TO_SCHEME_MAP = 0;
44
45
    /** Config key */
46
    const KEY_VALIDATION_RULE_SETS_DATA = self::KEY_MODEL_TO_SCHEME_MAP + 1;
47
48
    /** Config key */
49
    const KEY_RELATIONSHIP_PAGING_SIZE = self::KEY_VALIDATION_RULE_SETS_DATA + 1;
50
51
    /** Config key */
52
    const KEY_JSON_ENCODE_OPTIONS = self::KEY_RELATIONSHIP_PAGING_SIZE + 1;
53
54
    /** Config key */
55
    const KEY_JSON_ENCODE_DEPTH = self::KEY_JSON_ENCODE_OPTIONS + 1;
56
57
    /** Config key */
58
    const KEY_IS_SHOW_VERSION = self::KEY_JSON_ENCODE_DEPTH + 1;
59
60
    /** Config key */
61
    const KEY_META = self::KEY_IS_SHOW_VERSION + 1;
62
63
    /** Config key */
64
    const KEY_URI_PREFIX = self::KEY_META + 1;
65
66
    /** Config key */
67
    const KEY_LAST = self::KEY_URI_PREFIX + 1;
68
69
    /**
70
     * @return array
71
     */
72
    public function get(): array
73
    {
74
        $jsonOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES;
75
76
        return [
77
            static::KEY_MODEL_TO_SCHEME_MAP       => $this->createModelToSchemeMap(),
78
            static::KEY_VALIDATION_RULE_SETS_DATA => $this->createRulesSetData(),
79
            static::KEY_RELATIONSHIP_PAGING_SIZE  => 20,
80
            static::KEY_JSON_ENCODE_OPTIONS       => $jsonOptions,
81
            static::KEY_JSON_ENCODE_DEPTH         => 512,
82
            static::KEY_IS_SHOW_VERSION           => false,
83
            static::KEY_META                      => null,
84
            static::KEY_URI_PREFIX                => null,
85
        ];
86
    }
87
88
    /**
89
     * @return array
90
     */
91
    private function createModelToSchemeMap(): array
92
    {
93
        $map   = [];
94
        $types = [];
95
        foreach ($this->selectClasses($this->getSchemesPath(), SchemaInterface::class) as $schemeClass) {
96
            assert(
97
                is_string($schemeClass) &&
98
                class_exists($schemeClass) &&
99
                array_key_exists(SchemaInterface::class, class_implements($schemeClass))
100
            );
101
            /** @var SchemaInterface $schemeClass */
102
            $modelClass   = $schemeClass::MODEL;
103
            $resourceType = $schemeClass::TYPE;
104
105
            assert(is_string($modelClass) === true && empty($modelClass) === false);
106
            assert(is_string($resourceType) === true && empty($resourceType) === false);
107
108
            // By default it checks that all Schemes have unique resource types. That's a legit case
109
            // to have multiple Schemes for a same resource type however it's more likely that developer
110
            // just forgot to set a unique one. If you do need multiple Schemes for a resource feel free
111
            // to set to turn off this check.
112
            assert(
113
                $this->requireUniqueTypes === false || array_key_exists($resourceType, $types) === false,
114
                "Are you sure it's not an error to use resource type `$resourceType` more than once?"
115
            );
116
            $types[$resourceType] = true;
117
118
            $map[$modelClass] = $schemeClass;
119
        }
120
121
        return $map;
122
    }
123
124
    /**
125
     * @return array
126
     */
127
    private function createRulesSetData(): array
128
    {
129
        $serializer = new JsonApiRuleSerializer();
130
        foreach ($this->selectClasses($this->getRuleSetsPath(), JsonApiRuleSetInterface::class) as $setClass) {
131
            /** @var string $setName */
132
            $setName = $setClass;
133
            assert(
134
                is_string($setClass) &&
135
                class_exists($setClass) &&
136
                array_key_exists(JsonApiRuleSetInterface::class, class_implements($setClass))
137
            );
138
            /** @var JsonApiRuleSetInterface $setClass */
139
            $serializer->addResourceRules(
140
                $setName,
141
                $setClass::getIdRule(),
142
                $setClass::getTypeRule(),
143
                $setClass::getAttributeRules(),
144
                $setClass::getToOneRelationshipRules(),
145
                $setClass::getToManyRelationshipRules()
146
            );
147
        }
148
149
        $ruleSetsData = $serializer->getData();
150
151
        return $ruleSetsData;
152
    }
153
}
154