Completed
Push — ezp_30785 ( df199e )
by
unknown
13:58
created

FieldNameResolver::getFieldName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 4
dl 0
loc 23
rs 9.552
c 0
b 0
f 0
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
namespace eZ\Publish\Core\Search\Common;
10
11
use eZ\Publish\SPI\Persistence\Content\Type\Handler as ContentTypeHandler;
12
use eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface;
13
use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
14
use eZ\Publish\API\Repository\Values\Content\Query\Criterion;
15
use RuntimeException;
16
17
/**
18
 * Provides search backend field name resolving for criteria and sort clauses
19
 * targeting Content fields.
20
 */
21
class FieldNameResolver
22
{
23
    /**
24
     * Field registry.
25
     *
26
     * @var \eZ\Publish\Core\Search\Common\FieldRegistry
27
     */
28
    protected $fieldRegistry;
29
30
    /**
31
     * Content type handler.
32
     *
33
     * @var \eZ\Publish\SPI\Persistence\Content\Type\Handler
34
     */
35
    protected $contentTypeHandler;
36
37
    /**
38
     * Field name generator.
39
     *
40
     * @var \eZ\Publish\Core\Search\Common\FieldNameGenerator
41
     */
42
    protected $nameGenerator;
43
44
    /**
45
     * Create from search field registry, content type handler and field name generator.
46
     *
47
     * @param \eZ\Publish\Core\Search\Common\FieldRegistry $fieldRegistry
48
     * @param \eZ\Publish\SPI\Persistence\Content\Type\Handler $contentTypeHandler
49
     * @param \eZ\Publish\Core\Search\Common\FieldNameGenerator $nameGenerator
50
     */
51
    public function __construct(
52
        FieldRegistry $fieldRegistry,
53
        ContentTypeHandler $contentTypeHandler,
54
        FieldNameGenerator $nameGenerator
55
    ) {
56
        $this->fieldRegistry = $fieldRegistry;
57
        $this->contentTypeHandler = $contentTypeHandler;
58
        $this->nameGenerator = $nameGenerator;
59
    }
60
61
    /**
62
     * Get content type, field definition and field type mapping information.
63
     *
64
     * Returns an array in the form:
65
     *
66
     * <code>
67
     *  array(
68
     *      "<ContentType identifier>" => array(
69
     *          "<FieldDefinition identifier>" => array(
70
     *              "field_definition_id" => "<FieldDefinition id>",
71
     *              "field_type_identifier" => "<FieldType identifier>",
72
     *          ),
73
     *          ...
74
     *      ),
75
     *      ...
76
     *  )
77
     * </code>
78
     *
79
     * @return array[]
80
     */
81
    protected function getSearchableFieldMap()
82
    {
83
        return $this->contentTypeHandler->getSearchableFieldMap();
84
    }
85
86
    /**
87
     * For the given parameters returns a set of search backend field names to search on.
88
     *
89
     * The method will check for custom fields if given $criterion implements
90
     * CustomFieldInterface. With optional parameters $fieldTypeIdentifier and
91
     * $name specific field type and field from its Indexable implementation
92
     * can be targeted.
93
     *
94
     * @deprecated since 6.2, use getFieldTypes instead
95
     *
96
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
97
     * @see \eZ\Publish\SPI\FieldType\Indexable
98
     *
99
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
100
     * @param string $fieldDefinitionIdentifier
101
     * @param null|string $fieldTypeIdentifier
102
     * @param null|string $name
103
     *
104
     * @return string[]
105
     */
106
    public function getFieldNames(
107
        Criterion $criterion,
108
        $fieldDefinitionIdentifier,
109
        $fieldTypeIdentifier = null,
110
        $name = null
111
    ) {
112
        $fieldTypeNameMap = $this->getFieldTypes($criterion, $fieldDefinitionIdentifier, $fieldTypeIdentifier, $name);
113
114
        return array_keys($fieldTypeNameMap);
115
    }
116
117
    public function getFieldName(
118
        Criterion $criterion,
119
        string $contentTypeIdentifier,
120
        string $fieldDefinitionIdentifier,
121
        ?string $name = null
122
    ): ?string {
123
        $fieldMap = $this->getSearchableFieldMap();
124
125
        if (!isset($fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier])) {
126
            return null;
127
        }
128
129
        $mapping = $this->getIndexFieldName(
130
            $criterion,
131
            $contentTypeIdentifier,
132
            $fieldDefinitionIdentifier,
133
            $fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier]['field_type_identifier'],
134
            $name,
135
            false
136
        );
137
138
        return array_key_first($mapping);
139
    }
140
141
    /**
142
     * For the given parameters returns a set of search backend field names/types to search on.
143
     *
144
     * The method will check for custom fields if given $criterion implements
145
     * CustomFieldInterface. With optional parameters $fieldTypeIdentifier and
146
     * $name specific field type and field from its Indexable implementation
147
     * can be targeted.
148
     *
149
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
150
     * @see \eZ\Publish\SPI\FieldType\Indexable
151
     *
152
     * @param \eZ\Publish\API\Repository\Values\Content\Query\Criterion $criterion
153
     * @param string $fieldDefinitionIdentifier
154
     * @param null|string $fieldTypeIdentifier
155
     * @param null|string $name
156
     *
157
     * @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...
158
     */
159
    public function getFieldTypes(
160
        Criterion $criterion,
161
        $fieldDefinitionIdentifier,
162
        $fieldTypeIdentifier = null,
163
        $name = null
164
    ) {
165
        $fieldMap = $this->getSearchableFieldMap();
166
        $fieldTypeNameMap = [];
167
168
        foreach ($fieldMap as $contentTypeIdentifier => $fieldIdentifierMap) {
169
            // First check if field exists in the current ContentType, there is nothing to do if it doesn't
170
            if (!isset($fieldIdentifierMap[$fieldDefinitionIdentifier])) {
171
                continue;
172
            }
173
174
            // If $fieldTypeIdentifier is given it must match current field definition
175
            if (
176
                $fieldTypeIdentifier !== null &&
177
                $fieldTypeIdentifier !== $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier']
178
            ) {
179
                continue;
180
            }
181
182
            $fieldNameWithSearchType = $this->getIndexFieldName(
183
                $criterion,
184
                $contentTypeIdentifier,
185
                $fieldDefinitionIdentifier,
186
                $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier'],
187
                $name,
188
                false
189
            );
190
191
            $fieldNames = array_keys($fieldNameWithSearchType);
192
            $fieldName = reset($fieldNames);
193
194
            $fieldTypeNameMap[$fieldName] = $fieldNameWithSearchType[$fieldName];
195
        }
196
197
        return $fieldTypeNameMap;
198
    }
199
200
    /**
201
     * For the given parameters returns search backend field name to sort on or
202
     * null if the field could not be found.
203
     *
204
     * The method will check for custom fields if given $sortClause implements
205
     * CustomFieldInterface. With optional parameter $name specific field from
206
     * field type's Indexable implementation can be targeted.
207
     *
208
     * Will return null if no sortable field is found.
209
     *
210
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
211
     * @see \eZ\Publish\SPI\FieldType\Indexable
212
     *
213
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
214
     * @param string $contentTypeIdentifier
215
     * @param string $fieldDefinitionIdentifier
216
     * @param null|string $name
217
     *
218
     * @return null|string
219
     */
220
    public function getSortFieldName(
221
        SortClause $sortClause,
222
        $contentTypeIdentifier,
223
        $fieldDefinitionIdentifier,
224
        $name = null
225
    ) {
226
        $fieldMap = $this->getSearchableFieldMap();
227
228
        // First check if field exists in type, there is nothing to do if it doesn't
229
        if (!isset($fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier])) {
230
            return null;
231
        }
232
233
        $fieldName = array_keys($this->getIndexFieldName(
234
            $sortClause,
235
            $contentTypeIdentifier,
236
            $fieldDefinitionIdentifier,
237
            $fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier]['field_type_identifier'],
238
            $name,
239
            true
240
        ));
241
242
        return reset($fieldName);
243
    }
244
245
    /**
246
     * Returns index field name for the given parameters.
247
     *
248
     * @param object $criterionOrSortClause
249
     * @param string $contentTypeIdentifier
250
     * @param string $fieldDefinitionIdentifier
251
     * @param string $fieldTypeIdentifier
252
     * @param string $name
253
     * @param bool $isSortField
254
     *
255
     * @return string
256
     */
257
    public function getIndexFieldName(
258
        $criterionOrSortClause,
259
        $contentTypeIdentifier,
260
        $fieldDefinitionIdentifier,
261
        $fieldTypeIdentifier,
262
        $name,
263
        $isSortField
264
    ) {
265
        // If criterion or sort clause implements CustomFieldInterface and custom field is set for
266
        // ContentType/FieldDefinition, return it
267
        if (
268
            $criterionOrSortClause instanceof CustomFieldInterface &&
269
            $customFieldName = $criterionOrSortClause->getCustomField(
270
                $contentTypeIdentifier,
271
                $fieldDefinitionIdentifier
272
            )
273
        ) {
274
            return [$customFieldName => null];
275
        }
276
277
        // Else, generate field name from field type's index definition
278
279
        $indexFieldType = $this->fieldRegistry->getType($fieldTypeIdentifier);
280
281
        // If $name is not given use default field name
282
        if ($name === null) {
283
            if ($isSortField) {
284
                $name = $indexFieldType->getDefaultSortField();
285
            } else {
286
                $name = $indexFieldType->getDefaultMatchField();
287
            }
288
        }
289
290
        $indexDefinition = $indexFieldType->getIndexDefinition();
291
292
        // Should only happen by mistake, so let's throw if it does
293
        if (!isset($indexDefinition[$name])) {
294
            throw new RuntimeException(
295
                "Could not find '{$name}' field in '{$fieldTypeIdentifier}' field type's index definition"
296
            );
297
        }
298
299
        $field = $this->nameGenerator->getTypedName(
300
            $this->nameGenerator->getName(
301
                $name,
302
                $fieldDefinitionIdentifier,
303
                $contentTypeIdentifier
304
            ),
305
            $indexDefinition[$name]
306
        );
307
308
        return [$field => $indexDefinition[$name]];
309
    }
310
}
311