Completed
Push — permissions_subtree_internal ( 23a533...b0d47a )
by André
77:49 queued 53:51
created

FieldNameResolver::getFieldNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 10
rs 9.4285
cc 1
eloc 7
nc 1
nop 4
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 array
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
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
            $fieldName = $this->getIndexFieldName(
161
                $criterion,
162
                $contentTypeIdentifier,
163
                $fieldDefinitionIdentifier,
164
                $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier'],
165
                $name,
166
                false
167
            );
168
            $fieldType = $this->fieldRegistry->getType(
169
                $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier']
170
            );
171
            $fieldTypeNameMap[$fieldName] = $fieldType;
172
        }
173
174
        return $fieldTypeNameMap;
175
    }
176
177
    /**
178
     * For the given parameters returns search backend field name to sort on or
179
     * null if the field could not be found.
180
     *
181
     * The method will check for custom fields if given $sortClause implements
182
     * CustomFieldInterface. With optional parameter $name specific field from
183
     * field type's Indexable implementation can be targeted.
184
     *
185
     * Will return null if no sortable field is found.
186
     *
187
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
188
     * @see \eZ\Publish\SPI\FieldType\Indexable
189
     *
190
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
191
     * @param string $contentTypeIdentifier
192
     * @param string $fieldDefinitionIdentifier
193
     * @param null|string $name
194
     *
195
     * @return null|string
196
     */
197
    public function getSortFieldName(
198
        SortClause $sortClause,
199
        $contentTypeIdentifier,
200
        $fieldDefinitionIdentifier,
201
        $name = null
202
    ) {
203
        $fieldMap = $this->getSearchableFieldMap();
204
205
        // First check if field exists in type, there is nothing to do if it doesn't
206
        if (!isset($fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier])) {
207
            return null;
208
        }
209
210
        return $this->getIndexFieldName(
211
            $sortClause,
212
            $contentTypeIdentifier,
213
            $fieldDefinitionIdentifier,
214
            $fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier]['field_type_identifier'],
215
            $name,
216
            true
217
        );
218
    }
219
220
    /**
221
     * Returns index field name for the given parameters.
222
     *
223
     * @param object $criterionOrSortClause
224
     * @param string $contentTypeIdentifier
225
     * @param string $fieldDefinitionIdentifier
226
     * @param string $fieldTypeIdentifier
227
     * @param string $name
228
     * @param bool $isSortField
229
     *
230
     * @return string
231
     */
232
    public function getIndexFieldName(
233
        $criterionOrSortClause,
234
        $contentTypeIdentifier,
235
        $fieldDefinitionIdentifier,
236
        $fieldTypeIdentifier,
237
        $name,
238
        $isSortField
239
    ) {
240
        // If criterion or sort clause implements CustomFieldInterface and custom field is set for
241
        // ContentType/FieldDefinition, return it
242
        if (
243
            $criterionOrSortClause instanceof CustomFieldInterface &&
244
            $customFieldName = $criterionOrSortClause->getCustomField(
245
                $contentTypeIdentifier,
246
                $fieldDefinitionIdentifier
247
            )
248
        ) {
249
            return $customFieldName;
250
        }
251
252
        // Else, generate field name from field type's index definition
253
254
        $indexFieldType = $this->fieldRegistry->getType($fieldTypeIdentifier);
255
256
        // If $name is not given use default field name
257
        if ($name === null) {
258
            if ($isSortField) {
259
                $name = $indexFieldType->getDefaultSortField();
260
            } else {
261
                $name = $indexFieldType->getDefaultMatchField();
262
            }
263
        }
264
265
        $indexDefinition = $indexFieldType->getIndexDefinition();
266
267
        // Should only happen by mistake, so let's throw if it does
268
        if (!isset($indexDefinition[$name])) {
269
            throw new RuntimeException(
270
                "Could not find '{$name}' field in '{$fieldTypeIdentifier}' field type's index definition"
271
            );
272
        }
273
274
        return $this->nameGenerator->getTypedName(
275
            $this->nameGenerator->getName(
276
                $name,
277
                $fieldDefinitionIdentifier,
278
                $contentTypeIdentifier
279
            ),
280
            $indexDefinition[$name]
281
        );
282
    }
283
}
284