ConfigValidator::checkClients()   A
last analyzed

Complexity

Conditions 3
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
rs 10
c 0
b 0
f 0
cc 3
nc 2
nop 2
1
<?php
2
3
namespace Mdiyakov\DoctrineSolrBundle\Config;
4
5
use Mdiyakov\DoctrineSolrBundle\Exception\ClientConfigException;
6
use Mdiyakov\DoctrineSolrBundle\Exception\ConfigFieldException;
7
use Mdiyakov\DoctrineSolrBundle\Exception\EntityClassConfigException;
8
use Mdiyakov\DoctrineSolrBundle\Exception\FilterConfigException;
9
use Mdiyakov\DoctrineSolrBundle\Exception\RequiredFieldException;
10
use Mdiyakov\DoctrineSolrBundle\Exception\SchemaConfigException;
11
use Mdiyakov\DoctrineSolrBundle\Exception\SchemaNotFoundException;
12
13
class ConfigValidator
14
{
15
    /**
16
     * @var string[]
17
     */
18
    private $discriminatorValues = [];
19
20
    /**
21
     * @var string[]
22
     */
23
    private $entityClasses = [];
24
25
    /**
26
     * @param string[][] $entityConfig
27
     * @param string[][] $schemes
28
     * @param string[][] $filters
29
     * @param string[] $clients
30
     * @throws SchemaNotFoundException
31
     */
32
    public function validate($entityConfig, $schemes, $filters, $clients)
33
    {
34
        if (!array_key_exists($entityConfig['schema'], $schemes)) {
35
            throw new SchemaNotFoundException(
36
                sprintf('Schema "%s" is not found in "schema" config section. Check config.yml', $entityConfig['schema'])
0 ignored issues
show
Bug introduced by
$entityConfig['schema'] of type string[] is incompatible with the type string expected by parameter $args of sprintf(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

36
                sprintf('Schema "%s" is not found in "schema" config section. Check config.yml', /** @scrutinizer ignore-type */ $entityConfig['schema'])
Loading history...
37
            );
38
        }
39
40
        $schemaConfig = $schemes[$entityConfig['schema']];
41
        $this->checkEntityContainRequiredFields($entityConfig['class'], $schemaConfig);
0 ignored issues
show
Bug introduced by
$entityConfig['class'] of type string[] is incompatible with the type string expected by parameter $entityClass of Mdiyakov\DoctrineSolrBun...ContainRequiredFields(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

41
        $this->checkEntityContainRequiredFields(/** @scrutinizer ignore-type */ $entityConfig['class'], $schemaConfig);
Loading history...
Bug introduced by
$schemaConfig of type string[] is incompatible with the type array<mixed,string[]> expected by parameter $schemaConfig of Mdiyakov\DoctrineSolrBun...ContainRequiredFields(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

41
        $this->checkEntityContainRequiredFields($entityConfig['class'], /** @scrutinizer ignore-type */ $schemaConfig);
Loading history...
42
        $this->checkClassesForUnique($entityConfig['class']);
43
        $this->checkConfigFields($entityConfig, $schemaConfig);
0 ignored issues
show
Bug introduced by
$schemaConfig of type string[] is incompatible with the type array<mixed,string[]> expected by parameter $schemaConfig of Mdiyakov\DoctrineSolrBun...or::checkConfigFields(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

43
        $this->checkConfigFields($entityConfig, /** @scrutinizer ignore-type */ $schemaConfig);
Loading history...
44
        $this->checkFilters($entityConfig, $filters);
45
        $this->checkClients($schemaConfig, $clients);
46
        $this->checkDocumentFieldNamesAreUnique($schemaConfig);
47
    }
48
49
    /**
50
     * @param string $entityClass
51
     * @param string[][] $schemaConfig
52
     * @throws RequiredFieldException
53
     */
54
    private function checkEntityContainRequiredFields($entityClass, $schemaConfig)
55
    {
56
        foreach ($schemaConfig['fields'] as $fieldConfig) {
57
            $this->checkEntityHasField($entityClass, $fieldConfig['entity_field_name']);
58
        }
59
    }
60
61
    /**
62
     * @param string[][] $entityConfig
63
     * @param string[][] $schemaConfig
64
     * @throws ConfigFieldException
65
     */
66
    private function checkConfigFields($entityConfig, $schemaConfig)
67
    {
68
        $schemaConfigEntityFields = $schemaConfig['config_entity_fields'];
69
        if (!is_array($schemaConfigEntityFields)) {
0 ignored issues
show
introduced by
The condition is_array($schemaConfigEntityFields) is always true.
Loading history...
70
            return;
71
        }
72
73
        $configFields = $entityConfig['config'];
74
        if (!is_array($configFields)) {
0 ignored issues
show
introduced by
The condition is_array($configFields) is always true.
Loading history...
75
            throw new ConfigFieldException(
76
                sprintf('Config fields for "%s" entity are not defined. Check entity config', $entityConfig['class'])
77
            );
78
        }
79
        $configFieldsNames = [];
80
        foreach ($configFields as $configField) {
81
            $configFieldsNames[$configField['name']] = $configField['value'];
82
        }
83
84
        foreach ($schemaConfigEntityFields as $fieldConfig) {
85
            if (!array_key_exists($fieldConfig['config_field_name'], $configFieldsNames)) {
86
                throw new ConfigFieldException(
87
                    sprintf(
88
                        '"%s" config field is not defined in indexed_entities for entity %s',
89
                        $fieldConfig['config_field_name'],
90
                        $entityConfig['class']
0 ignored issues
show
Bug introduced by
$entityConfig['class'] of type string[] is incompatible with the type string expected by parameter $args of sprintf(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

90
                        /** @scrutinizer ignore-type */ $entityConfig['class']
Loading history...
91
                    )
92
                );
93
            }
94
95
            if ($fieldConfig['discriminator'] === true) {
96
                $discriminatorValue = $configFieldsNames[$fieldConfig['config_field_name']];
97
                if (in_array($discriminatorValue, $this->discriminatorValues)) {
98
                    throw new ConfigFieldException(
99
                        sprintf(
100
                            '"%s" discriminator value has already been used.
101
                            It seems there are two entity classes inside "indexed_entities" with identical discriminator config field value',
102
                            $discriminatorValue
103
                        )
104
                    );
105
                }
106
                $this->discriminatorValues[] =  $discriminatorValue;
107
            }
108
        }
109
    }
110
111
    /**
112
     * @param $schemaConfig
113
     * @param $clients
114
     * @throws ClientConfigException
115
     */
116
    private function checkClients($schemaConfig, $clients)
117
    {
118
        if (!empty($schemaConfig['client']) && !array_key_exists($schemaConfig['client'], $clients)) {
119
            throw new ClientConfigException(
120
                sprintf('Solarium client "%s" is not defined in "solarium_clients" section', $schemaConfig['client'])
121
            );
122
        }
123
    }
124
125
    /**
126
     * @param string[][] $entityConfig
127
     * @param string[][] $filters
128
     */
129
    private function checkFilters($entityConfig, $filters)
130
    {
131
        if (array_key_exists('filters', $entityConfig)) {
132
133
            $filtersKeys = array_fill_keys(
134
                array_merge(
135
                    array_keys($filters['fields']),
136
                    array_keys($filters['services'])
137
                ),
138
                true
139
            );
140
141
            foreach($entityConfig['filters'] as $filterName) {
142
                if (!array_key_exists($filterName, $filtersKeys)) {
143
                    throw new FilterConfigException(
144
                        sprintf('Filter "%s" is not defined in "filters" section', $filterName)
145
                    );
146
                }
147
            }
148
149
            if (array_key_exists('fields', $filters) && is_array($filters['fields'])) {
150
                foreach ($filters['fields'] as $filterName => $filterConfig) {
151
                    try {
152
                        $this->checkEntityHasField($entityConfig['class'], $filterConfig['entity_field_name']);
153
                    } catch (RequiredFieldException $e) {
154
                        $message = $e->getMessage() . ' Error occurred for "filters" section. Please check the filters configuration in config.yml';
155
                        throw new RequiredFieldException($message);
156
                    }
157
158
                }
159
            }
160
        }
161
    }
162
163
    /**
164
     * @param string[][] $schemaConfig
165
     * @throws SchemaConfigException
166
     */
167
    private function checkDocumentFieldNamesAreUnique($schemaConfig)
168
    {
169
        $schemaFields = [ $schemaConfig['config_entity_fields'], $schemaConfig['fields'] ];
170
        $documentFieldsNames = [];
171
172
        while ($fieldsConfig = array_shift($schemaFields)) {
173
            foreach ($fieldsConfig as $fieldConfig) {
174
                $documentFieldName = $fieldConfig['document_field_name'];
175
                if (array_key_exists($documentFieldName, $documentFieldsNames)) {
176
                    throw new SchemaConfigException(
177
                        sprintf('You have more than one fields with the same  document field name "%s"', $documentFieldName)
178
                    );
179
                }
180
                $documentFieldsNames[$documentFieldName] = true;
181
            }
182
        }
183
    }
184
185
    /**
186
     * @param string $entityClass
187
     * @param string $entityFieldName
188
     * @throws RequiredFieldException
189
     */
190
    private function checkEntityHasField($entityClass, $entityFieldName)
191
    {
192
        $reflection = new \ReflectionClass($entityClass);
193
        $getterMethodName = 'get' . ucfirst($entityFieldName);
194
        $isserMethodName = 'is' . ucfirst($entityFieldName);
195
196
        if ($reflection->hasMethod($getterMethodName)) {
197
            $getterReflectionMethod = new \ReflectionMethod($entityClass, $getterMethodName);
198
            if (!$getterReflectionMethod->isPublic()) {
199
                throw new RequiredFieldException(
200
                    sprintf(
201
                        'Getter method "%s" is not public in "%s".',
202
                        $getterMethodName,
203
                        $entityClass
204
                    )
205
                );
206
            }
207
        } elseif ($reflection->hasMethod($isserMethodName)) {
208
            $isserReflectionMethod = new \ReflectionMethod($entityClass, $isserMethodName);
209
            if (!$isserReflectionMethod->isPublic()) {
210
                throw new RequiredFieldException(
211
                    sprintf(
212
                        'Isser method "%s" is not public in "%s".',
213
                        $isserMethodName,
214
                        $entityClass
215
                    )
216
                );
217
            }
218
        } else {
219
            throw new RequiredFieldException(
220
                 sprintf(
221
                    'Either getter method "%s" or isser method "%s" is not found in %s.',
222
                    $getterMethodName,
223
                    $isserMethodName,
224
                    $entityClass
225
                )
226
            );
227
        }
228
    }
229
230
    /**
231
     * @param $entityClass
232
     * @throws EntityClassConfigException
233
     */
234
    private function checkClassesForUnique($entityClass)
235
    {
236
        if (!in_array($entityClass, $this->entityClasses)) {
237
            $this->entityClasses[] = $entityClass;
238
        } else {
239
            throw new EntityClassConfigException(
240
                sprintf(
241
                    'It seems entity class "%s" has been configured more than once inside "indexed_entities" section. You can not have different config for the single entity class',
242
                    $entityClass
243
                )
244
            );
245
        }
246
    }
247
}