Completed
Push — permissions_subtree_internal ( ee69eb...23a533 )
by André
57:14 queued 30:26
created

FieldNameResolver::getFieldNames()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 35
Code Lines 22

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 35
rs 8.439
cc 5
eloc 22
nc 4
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
     * @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 array
105
     */
106
    public function getFieldNames(
107
        Criterion $criterion,
108
        $fieldDefinitionIdentifier,
109
        $fieldTypeIdentifier = null,
110
        $name = null
111
    ) {
112
        $fieldMap = $this->getSearchableFieldMap();
113
        $fieldNames = [];
114
115
        foreach ($fieldMap as $contentTypeIdentifier => $fieldIdentifierMap) {
116
            // First check if field exists in the current ContentType, there is nothing to do if it doesn't
117
            if (!isset($fieldIdentifierMap[$fieldDefinitionIdentifier])) {
118
                continue;
119
            }
120
121
            // If $fieldTypeIdentifier is given it must match current field definition
122
            if (
123
                $fieldTypeIdentifier !== null &&
124
                $fieldTypeIdentifier !== $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier']
125
            ) {
126
                continue;
127
            }
128
129
            $fieldNames[] = $this->getIndexFieldName(
130
                $criterion,
131
                $contentTypeIdentifier,
132
                $fieldDefinitionIdentifier,
133
                $fieldIdentifierMap[$fieldDefinitionIdentifier]['field_type_identifier'],
134
                $name,
135
                false
136
            );
137
        }
138
139
        return $fieldNames;
140
    }
141
142
    /**
143
     * For the given parameters returns search backend field name to sort on or
144
     * null if the field could not be found.
145
     *
146
     * The method will check for custom fields if given $sortClause implements
147
     * CustomFieldInterface. With optional parameter $name specific field from
148
     * field type's Indexable implementation can be targeted.
149
     *
150
     * Will return null if no sortable field is found.
151
     *
152
     * @see \eZ\Publish\API\Repository\Values\Content\Query\CustomFieldInterface
153
     * @see \eZ\Publish\SPI\FieldType\Indexable
154
     *
155
     * @param \eZ\Publish\API\Repository\Values\Content\Query\SortClause $sortClause
156
     * @param string $contentTypeIdentifier
157
     * @param string $fieldDefinitionIdentifier
158
     * @param null|string $name
159
     *
160
     * @return null|string
161
     */
162
    public function getSortFieldName(
163
        SortClause $sortClause,
164
        $contentTypeIdentifier,
165
        $fieldDefinitionIdentifier,
166
        $name = null
167
    ) {
168
        $fieldMap = $this->getSearchableFieldMap();
169
170
        // First check if field exists in type, there is nothing to do if it doesn't
171
        if (!isset($fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier])) {
172
            return null;
173
        }
174
175
        return $this->getIndexFieldName(
176
            $sortClause,
177
            $contentTypeIdentifier,
178
            $fieldDefinitionIdentifier,
179
            $fieldMap[$contentTypeIdentifier][$fieldDefinitionIdentifier]['field_type_identifier'],
180
            $name,
181
            true
182
        );
183
    }
184
185
    /**
186
     * Returns index field name for the given parameters.
187
     *
188
     * @param object $criterionOrSortClause
189
     * @param string $contentTypeIdentifier
190
     * @param string $fieldDefinitionIdentifier
191
     * @param string $fieldTypeIdentifier
192
     * @param string $name
193
     * @param bool $isSortField
194
     *
195
     * @return string
196
     */
197
    public function getIndexFieldName(
198
        $criterionOrSortClause,
199
        $contentTypeIdentifier,
200
        $fieldDefinitionIdentifier,
201
        $fieldTypeIdentifier,
202
        $name,
203
        $isSortField
204
    ) {
205
        // If criterion or sort clause implements CustomFieldInterface and custom field is set for
206
        // ContentType/FieldDefinition, return it
207
        if (
208
            $criterionOrSortClause instanceof CustomFieldInterface &&
209
            $customFieldName = $criterionOrSortClause->getCustomField(
210
                $contentTypeIdentifier,
211
                $fieldDefinitionIdentifier
212
            )
213
        ) {
214
            return $customFieldName;
215
        }
216
217
        // Else, generate field name from field type's index definition
218
219
        $indexFieldType = $this->fieldRegistry->getType($fieldTypeIdentifier);
220
221
        // If $name is not given use default field name
222
        if ($name === null) {
223
            if ($isSortField) {
224
                $name = $indexFieldType->getDefaultSortField();
225
            } else {
226
                $name = $indexFieldType->getDefaultMatchField();
227
            }
228
        }
229
230
        $indexDefinition = $indexFieldType->getIndexDefinition();
231
232
        // Should only happen by mistake, so let's throw if it does
233
        if (!isset($indexDefinition[$name])) {
234
            throw new RuntimeException(
235
                "Could not find '{$name}' field in '{$fieldTypeIdentifier}' field type's index definition"
236
            );
237
        }
238
239
        return $this->nameGenerator->getTypedName(
240
            $this->nameGenerator->getName(
241
                $name,
242
                $fieldDefinitionIdentifier,
243
                $contentTypeIdentifier
244
            ),
245
            $indexDefinition[$name]
246
        );
247
    }
248
}
249