Completed
Push — develop ( c3a093...26b032 )
by Neomerx
07:17 queued 05:11
created

FluteSettings::get()   C

Complexity

Conditions 8
Paths 1

Size

Total Lines 74
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 53
CRAP Score 8

Importance

Changes 0
Metric Value
dl 0
loc 74
ccs 53
cts 53
cp 1
rs 6.2894
c 0
b 0
f 0
cc 8
eloc 54
nc 1
nop 1
crap 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php namespace Limoncello\Flute\Package;
2
3
use Generator;
4
use Limoncello\Contracts\Application\ApplicationConfigurationInterface as A;
5
use Limoncello\Contracts\Settings\Packages\FluteSettingsInterface;
6
use Limoncello\Flute\Contracts\Schema\SchemaInterface;
7
use Limoncello\Flute\Contracts\Validation\FormRuleSetInterface;
8
use Limoncello\Flute\Contracts\Validation\JsonApiRuleSetInterface;
9
use Limoncello\Flute\Contracts\Validation\QueryRuleSetInterface;
10
use Limoncello\Flute\Validation\Form\Execution\AttributeRulesSerializer;
11
use Limoncello\Flute\Validation\JsonApi\Execution\JsonApiRuleSerializer;
12
use Neomerx\JsonApi\Exceptions\JsonApiException;
13
14
/**
15
 * @package Limoncello\Flute
16
 */
17
abstract class FluteSettings implements FluteSettingsInterface
18
{
19
    /**
20
     * Namespace for string resources.
21
     */
22
    const VALIDATION_NAMESPACE = 'Limoncello.Flute.Validation';
23
24
    /**
25
     * @param string $path
26
     * @param string $implementClassName
27
     *
28
     * @return Generator
29
     */
30
    abstract protected function selectClasses(string $path, string $implementClassName): Generator;
31
32
    /**
33
     * @param array $appConfig
34
     *
35
     * @return array
36
     */
37 28
    final public function get(array $appConfig): array
38
    {
39 28
        $defaults = $this->getSettings();
40
41 28
        $defaults[static::KEY_ROUTES_FOLDER]          = $appConfig[A::KEY_ROUTES_FOLDER];
42 28
        $defaults[static::KEY_WEB_CONTROLLERS_FOLDER] = $appConfig[A::KEY_WEB_CONTROLLERS_FOLDER];
43
44 28
        $apiFolder        = $defaults[static::KEY_API_FOLDER] ?? null;
45 28
        $valRulesFolder   = $defaults[static::KEY_JSON_VALIDATION_RULES_FOLDER] ?? null;
46 28
        $jsonCtrlFolder   = $defaults[static::KEY_JSON_CONTROLLERS_FOLDER] ?? null;
47 28
        $schemesFolder    = $defaults[static::KEY_SCHEMAS_FOLDER] ?? null;
48 28
        $schemesFileMask  = $defaults[static::KEY_SCHEMAS_FILE_MASK] ?? null;
49 28
        $jsonValFolder    = $defaults[static::KEY_JSON_VALIDATORS_FOLDER] ?? null;
50 28
        $jsonValFileMask  = $defaults[static::KEY_JSON_VALIDATORS_FILE_MASK] ?? null;
51 28
        $formsValFolder   = $defaults[static::KEY_FORM_VALIDATORS_FOLDER] ?? null;
52 28
        $formsValFileMask = $defaults[static::KEY_FORM_VALIDATORS_FILE_MASK] ?? null;
53 28
        $queryValFolder   = $defaults[static::KEY_QUERY_VALIDATORS_FOLDER] ?? null;
54 28
        $queryValFileMask = $defaults[static::KEY_QUERY_VALIDATORS_FILE_MASK] ?? null;
55
56 28
        assert(
57 28
            $apiFolder !== null && empty(glob($apiFolder)) === false,
58 28
            "Invalid API folder `$apiFolder`."
59
        );
60 28
        assert(
61 28
            $valRulesFolder !== null && empty(glob($valRulesFolder)) === false,
62 28
            "Invalid validation rules folder `$valRulesFolder`."
63
        );
64 28
        assert(
65 28
            $jsonCtrlFolder !== null && empty(glob($jsonCtrlFolder)) === false,
66 28
            "Invalid JSON API controllers' folder `$jsonCtrlFolder`."
67
        );
68 28
        assert(
69 28
            $schemesFolder !== null && empty(glob($schemesFolder)) === false,
70 28
            "Invalid Schemes folder `$schemesFolder`."
71
        );
72 28
        assert(empty($schemesFileMask) === false, "Invalid Schemes file mask `$schemesFileMask`.");
73 28
        assert(
74 28
            $jsonValFolder !== null && empty(glob($jsonValFolder)) === false,
75 28
            "Invalid JSON Validators folder `$jsonValFolder`."
76
        );
77 28
        assert(empty($jsonValFileMask) === false, "Invalid JSON Validators file mask `$jsonValFileMask`.");
78 28
        assert(
79 28
            $formsValFolder !== null && empty(glob($formsValFolder)) === false,
80 28
            "Invalid Forms Validators folder `$formsValFolder`."
81
        );
82 28
        assert(empty($formsValFileMask) === false, "Invalid Forms Validators file mask `$formsValFileMask`.");
83 28
        assert(
84 28
            $queryValFolder !== null && empty(glob($queryValFolder)) === false,
85 28
            "Invalid Query Validators folder `$queryValFolder`."
86
        );
87 28
        assert(empty($queryValFileMask) === false, "Invalid Query Validators file mask `$queryValFileMask`.");
88
89 28
        $schemesPath         = $schemesFolder . DIRECTORY_SEPARATOR . $schemesFileMask;
90 28
        $jsonValidatorsPath  = $jsonValFolder . DIRECTORY_SEPARATOR . $jsonValFileMask;
91 28
        $formsValidatorsPath = $formsValFolder . DIRECTORY_SEPARATOR . $formsValFileMask;
92 28
        $queryValidatorsPath = $queryValFolder . DIRECTORY_SEPARATOR . $queryValFileMask;
93
94 28
        $requireUniqueTypes = $defaults[static::KEY_SCHEMAS_REQUIRE_UNIQUE_TYPES] ?? true;
95
96 28
        $doNotLogExceptions = $defaults[static::KEY_DO_NOT_LOG_EXCEPTIONS_LIST] ?? [];
97 28
        unset($defaults[static::KEY_DO_NOT_LOG_EXCEPTIONS_LIST]);
98
99
        return $defaults + [
100 28
                static::KEY_DO_NOT_LOG_EXCEPTIONS_LIST__AS_KEYS => array_flip($doNotLogExceptions),
101
102 28
                static::KEY_MODEL_TO_SCHEME_MAP => $this->createModelToSchemeMap($schemesPath, $requireUniqueTypes),
103
104 28
                static::KEY_JSON_VALIDATION_RULE_SETS_DATA =>
105 28
                    $this->createJsonValidationRulesSetData($jsonValidatorsPath),
106
107 28
                static::KEY_ATTRIBUTE_VALIDATION_RULE_SETS_DATA =>
108 28
                    $this->createValidationAttributeRulesSetData($formsValidatorsPath, $queryValidatorsPath),
109
            ];
110
    }
111
112
    /**
113
     * @return array
114
     */
115 28
    protected function getSettings(): array
116
    {
117 28
        $jsonOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_UNESCAPED_SLASHES;
118
119
        return [
120 28
            static::KEY_SCHEMAS_REQUIRE_UNIQUE_TYPES              => true,
121 28
            static::KEY_SCHEMAS_FILE_MASK                         => '*.php',
122 28
            static::KEY_JSON_VALIDATORS_FILE_MASK                 => '*.php',
123 28
            static::KEY_FORM_VALIDATORS_FILE_MASK                 => '*.php',
124 28
            static::KEY_QUERY_VALIDATORS_FILE_MASK                => '*.php',
125 28
            static::KEY_THROWABLE_TO_JSON_API_EXCEPTION_CONVERTER => null,
126 28
            static::KEY_HTTP_CODE_FOR_UNEXPECTED_THROWABLE        => 500,
127 28
            static::KEY_DEFAULT_PAGING_SIZE                       => 20,
128 28
            static::KEY_MAX_PAGING_SIZE                           => 100,
129 28
            static::KEY_JSON_ENCODE_OPTIONS                       => $jsonOptions,
130 28
            static::KEY_JSON_ENCODE_DEPTH                         => 512,
131 28
            static::KEY_IS_SHOW_VERSION                           => false,
132 28
            static::KEY_META                                      => null,
133 28
            static::KEY_URI_PREFIX                                => null,
134
135 28
            static::KEY_DO_NOT_LOG_EXCEPTIONS_LIST => [
136
                JsonApiException::class,
137
            ],
138
        ];
139
    }
140
141
    /**
142
     * @param string $schemesPath
143
     * @param bool   $requireUniqueTypes
144
     *
145
     * @return array
146
     */
147 28
    private function createModelToSchemeMap(string $schemesPath, bool $requireUniqueTypes): array
148
    {
149 28
        $map   = [];
150 28
        $types = [];
151 28
        foreach ($this->selectClasses($schemesPath, SchemaInterface::class) as $schemeClass) {
152 28
            assert(
153 28
                is_string($schemeClass) &&
154 28
                class_exists($schemeClass) &&
155 28
                array_key_exists(SchemaInterface::class, class_implements($schemeClass))
156
            );
157
            /** @var SchemaInterface $schemeClass */
158 28
            $modelClass   = $schemeClass::MODEL;
159 28
            $resourceType = $schemeClass::TYPE;
160
161 28
            assert(is_string($modelClass) === true && empty($modelClass) === false);
162 28
            assert(is_string($resourceType) === true && empty($resourceType) === false);
163
164
            // By default it checks that all Schemes have unique resource types. That's a legit case
165
            // to have multiple Schemes for a same resource type however it's more likely that developer
166
            // just forgot to set a unique one. If you do need multiple Schemes for a resource feel free
167
            // to set to turn off this check.
168 28
            assert(
169 28
                $requireUniqueTypes === false || array_key_exists($resourceType, $types) === false,
170 28
                "Are you sure it's not an error to use resource type `$resourceType` more than once?"
171
            );
172 28
            $types[$resourceType] = true;
173
174 28
            $map[$modelClass] = $schemeClass;
175
        }
176
177 28
        return $map;
178
    }
179
180
    /**
181
     * @param string $validatorsPath
182
     *
183
     * @return array
184
     */
185 28
    private function createJsonValidationRulesSetData(string $validatorsPath): array
186
    {
187 28
        $serializer = new JsonApiRuleSerializer();
188 28
        foreach ($this->selectClasses($validatorsPath, JsonApiRuleSetInterface::class) as $setClass) {
189
            /** @var string $setName */
190 28
            $setName = $setClass;
191 28
            assert(
192 28
                is_string($setClass) &&
193 28
                class_exists($setClass) &&
194 28
                array_key_exists(JsonApiRuleSetInterface::class, class_implements($setClass))
195
            );
196
            /** @var JsonApiRuleSetInterface $setClass */
197 28
            $serializer->addResourceRules(
198 28
                $setName,
199 28
                $setClass::getIdRule(),
200 28
                $setClass::getTypeRule(),
201 28
                $setClass::getAttributeRules(),
202 28
                $setClass::getToOneRelationshipRules(),
203 28
                $setClass::getToManyRelationshipRules()
204
            );
205
        }
206
207 28
        $ruleSetsData = $serializer->getData();
208
209 28
        return $ruleSetsData;
210
    }
211
212
    /**
213
     * @param string $formsValPath
214
     * @param string $queriesValPath
215
     *
216
     * @return array
217
     */
218 28
    private function createValidationAttributeRulesSetData(string $formsValPath, string $queriesValPath): array
219
    {
220 28
        $serializer = new AttributeRulesSerializer();
221 28 View Code Duplication
        foreach ($this->selectClasses($formsValPath, FormRuleSetInterface::class) as $setClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
222
            /** @var string $setName */
223 28
            $setName = $setClass;
224 28
            assert(
225 28
                is_string($setClass) &&
226 28
                class_exists($setClass) &&
227 28
                array_key_exists(FormRuleSetInterface::class, class_implements($setClass))
228
            );
229
            /** @var FormRuleSetInterface $setClass */
230 28
            $serializer->addResourceRules($setName, $setClass::getAttributeRules());
231
        }
232 28 View Code Duplication
        foreach ($this->selectClasses($queriesValPath, QueryRuleSetInterface::class) as $setClass) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
233
            /** @var string $setName */
234 28
            $setName = $setClass;
235 28
            assert(
236 28
                is_string($setClass) &&
237 28
                class_exists($setClass) &&
238 28
                array_key_exists(QueryRuleSetInterface::class, class_implements($setClass))
239
            );
240
            /** @var QueryRuleSetInterface $setClass */
241 28
            $serializer->addResourceRules($setName, $setClass::getAttributeRules());
242
        }
243
244 28
        $ruleSetsData = $serializer->getData();
245
246 28
        return $ruleSetsData;
247
    }
248
}
249