Completed
Push — travis_trusty ( e78e49...6f0d6f )
by André
54:54 queued 34:46
created

FieldNameResolver   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 266
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 16
c 2
b 1
f 0
lcom 1
cbo 5
dl 0
loc 266
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
B getSortFieldName() 0 24 2
B getIndexFieldName() 0 53 6
A __construct() 0 9 1
A getSearchableFieldMap() 0 4 1
A getFieldNames() 0 10 1
B getFieldTypes() 0 40 5
1
<?php
2
3
/**
4
 * This file is part of the eZ Publish Kernel package.
5
 *
6
 * @copyright Copyright (C) eZ Systems AS. All rights reserved.
7
 * @license For full copyright and license information view LICENSE file distributed with this source code.
8
 *
9
 * @version //autogentag//
10
 */
11
namespace eZ\Publish\Core\Search\Common;
12
13
use eZ\Publish\SPI\Persistence\Content\Type\Handler as ContentTypeHandler;
14
use eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface;
15
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
16
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
17
use RuntimeException;
18
19
/**
20
 * Provides search backend field name resolving for criteria and sort clauses
21
 * targeting Content fields.
22
 */
23
class FieldNameResolver
24
{
25
    /**
26
     * Field registry.
27
     *
28
     * @var \eZ\Publish\Core\Search\Common\FieldRegistry
29
     */
30
    protected $fieldRegistry;
31
32
    /**
33
     * Content type handler.
34
     *
35
     * @var \eZ\Publish\SPI\Persistence\Content\Type\Handler
36
     */
37
    protected $contentTypeHandler;
38
39
    /**
40
     * Field name generator.
41
     *
42
     * @var \eZ\Publish\Core\Search\Common\FieldNameGenerator
43
     */
44
    protected $nameGenerator;
45
46
    /**
47
     * Create from search field registry, content type handler and field name generator.
48
     *
49
     * @param \eZ\Publish\Core\Search\Common\FieldRegistry $fieldRegistry
50
     * @param \eZ\Publish\SPI\Persistence\Content\Type\Handler $contentTypeHandler
51
     * @param \eZ\Publish\Core\Search\Common\FieldNameGenerator $nameGenerator
52
     */
53
    public function __construct(
54
        FieldRegistry $fieldRegistry,
55
        ContentTypeHandler $contentTypeHandler,
56
        FieldNameGenerator $nameGenerator
57
    ) {
58
        $this->fieldRegistry = $fieldRegistry;
59
        $this->contentTypeHandler = $contentTypeHandler;
60
        $this->nameGenerator = $nameGenerator;
61
    }
62
63
    /**
64
     * Get content type, field definition and field type mapping information.
65
     *
66
     * Returns an array in the form:
67
     *
68
     * <code>
69
     *  array(
70
     *      "<ContentType identifier>" => array(
71
     *          "<FieldDefinition identifier>" => array(
72
     *              "field_definition_id" => "<FieldDefinition id>",
73
     *              "field_type_identifier" => "<FieldType identifier>",
74
     *          ),
75
     *          ...
76
     *      ),
77
     *      ...
78
     *  )
79
     * </code>
80
     *
81
     * @return array[]
82
     */
83
    protected function getSearchableFieldMap()
84
    {
85
        return $this->contentTypeHandler->getSearchableFieldMap();
86
    }
87
88
    /**
89
     * For the given parameters returns a set of search backend field names to search on.
90
     *
91
     * The method will check for custom fields if given $criterion implements
92
     * CustomFieldInterface. With optional parameters $fieldTypeIdentifier and
93
     * $name specific field type and field from its Indexable implementation
94
     * can be targeted.
95
     *
96
     * @deprecated since 6.2, use getFieldTypes instead
97
     *
98
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
99
     * @see \eZ\Publish\SPI\FieldType\Indexable
100
     *
101
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
102
     * @param string $fieldDefinitionIdentifier
103
     * @param null|string $fieldTypeIdentifier
104
     * @param null|string $name
105
     *
106
     * @return string[]
107
     */
108
    public function getFieldNames(
109
        Criterion $criterion,
110
        $fieldDefinitionIdentifier,
111
        $fieldTypeIdentifier = null,
112
        $name = null
113
    ) {
114
        $fieldTypeNameMap = $this->getFieldTypes($criterion, $fieldDefinitionIdentifier, $fieldTypeIdentifier, $name);
115
116
        return array_keys($fieldTypeNameMap);
117
    }
118
119
    /**
120
     * For the given parameters returns a set of search backend field names/types to search on.
121
     *
122
     * The method will check for custom fields if given $criterion implements
123
     * CustomFieldInterface. With optional parameters $fieldTypeIdentifier and
124
     * $name specific field type and field from its Indexable implementation
125
     * can be targeted.
126
     *
127
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
128
     * @see \eZ\Publish\SPI\FieldType\Indexable
129
     *
130
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
131
     * @param string $fieldDefinitionIdentifier
132
     * @param null|string $fieldTypeIdentifier
133
     * @param null|string $name
134
     *
135
     * @return array<string, \eZ\Publish\SPI\Search\FieldType>
0 ignored issues
show
Documentation introduced by
The doc-type array<string, could not be parsed: Expected ">" at position 5, but found "end of type". (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
136
     */
137
    public function getFieldTypes(
138
        Criterion $criterion,
139
        $fieldDefinitionIdentifier,
140
        $fieldTypeIdentifier = null,
141
        $name = null
142
    ) {
143
        $fieldMap = $this->getSearchableFieldMap();
144
        $fieldTypeNameMap = [];
145
146
        foreach ($fieldMap as $contentTypeIdentifier => $fieldIdentifierMap) {
147
            // First check if field exists in the current ContentType, there is nothing to do if it doesn't
148
            if (!isset($fieldIdentifierMap[$fieldDefinitionIdentifier])) {
149
                continue;
150
            }
151
152
            // If $fieldTypeIdentifier is given it must match current field definition
153
            if (
154
                $fieldTypeIdentifier !== null &&
155
                $fieldTypeIdentifier !== $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier']
156
            ) {
157
                continue;
158
            }
159
160
            $fieldNameWithSearchType = $this->getIndexFieldName(
161
                $criterion,
162
                $contentTypeIdentifier,
163
                $fieldDefinitionIdentifier,
164
                $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier'],
165
                $name,
166
                false
167
            );
168
169
            $fieldNames = array_keys($fieldNameWithSearchType);
170
            $fieldName = reset($fieldNames);
171
172
            $fieldTypeNameMap[$fieldName] = $fieldNameWithSearchType[$fieldName];
173
        }
174
175
        return $fieldTypeNameMap;
176
    }
177
178
    /**
179
     * For the given parameters returns search backend field name to sort on or
180
     * null if the field could not be found.
181
     *
182
     * The method will check for custom fields if given $sortClause implements
183
     * CustomFieldInterface. With optional parameter $name specific field from
184
     * field type's Indexable implementation can be targeted.
185
     *
186
     * Will return null if no sortable field is found.
187
     *
188
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
189
     * @see \eZ\Publish\SPI\FieldType\Indexable
190
     *
191
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
192
     * @param string $contentTypeIdentifier
193
     * @param string $fieldDefinitionIdentifier
194
     * @param null|string $name
195
     *
196
     * @return null|string
197
     */
198
    public function getSortFieldName(
199
        SortClause $sortClause,
200
        $contentTypeIdentifier,
201
        $fieldDefinitionIdentifier,
202
        $name = null
203
    ) {
204
        $fieldMap = $this->getSearchableFieldMap();
205
206
        // First check if field exists in type, there is nothing to do if it doesn't
207
        if (!isset($fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier])) {
208
            return null;
209
        }
210
211
        $fieldName = array_keys($this->getIndexFieldName(
212
            $sortClause,
213
            $contentTypeIdentifier,
214
            $fieldDefinitionIdentifier,
215
            $fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier]['field_type_identifier'],
216
            $name,
217
            true
218
        ));
219
220
        return reset($fieldName);
221
    }
222
223
    /**
224
     * Returns index field name for the given parameters.
225
     *
226
     * @param object $criterionOrSortClause
227
     * @param string $contentTypeIdentifier
228
     * @param string $fieldDefinitionIdentifier
229
     * @param string $fieldTypeIdentifier
230
     * @param string $name
231
     * @param bool $isSortField
232
     *
233
     * @return string
234
     */
235
    public function getIndexFieldName(
236
        $criterionOrSortClause,
237
        $contentTypeIdentifier,
238
        $fieldDefinitionIdentifier,
239
        $fieldTypeIdentifier,
240
        $name,
241
        $isSortField
242
    ) {
243
        // If criterion or sort clause implements CustomFieldInterface and custom field is set for
244
        // ContentType/FieldDefinition, return it
245
        if (
246
            $criterionOrSortClause instanceof CustomFieldInterface &&
247
            $customFieldName = $criterionOrSortClause->getCustomField(
248
                $contentTypeIdentifier,
249
                $fieldDefinitionIdentifier
250
            )
251
        ) {
252
            return [$customFieldName => null];
253
        }
254
255
        // Else, generate field name from field type's index definition
256
257
        $indexFieldType = $this->fieldRegistry->getType($fieldTypeIdentifier);
258
259
        // If $name is not given use default field name
260
        if ($name === null) {
261
            if ($isSortField) {
262
                $name = $indexFieldType->getDefaultSortField();
263
            } else {
264
                $name = $indexFieldType->getDefaultMatchField();
265
            }
266
        }
267
268
        $indexDefinition = $indexFieldType->getIndexDefinition();
269
270
        // Should only happen by mistake, so let's throw if it does
271
        if (!isset($indexDefinition[$name])) {
272
            throw new RuntimeException(
273
                "Could not find '{$name}' field in '{$fieldTypeIdentifier}' field type's index definition"
274
            );
275
        }
276
277
        $field = $this->nameGenerator->getTypedName(
278
            $this->nameGenerator->getName(
279
                $name,
280
                $fieldDefinitionIdentifier,
281
                $contentTypeIdentifier
282
            ),
283
            $indexDefinition[$name]
284
        );
285
286
        return [$field => $indexDefinition[$name]];
287
    }
288
}
289