Completed
Push — master ( 00d60f...aabe5c )
by Dion
14s
created

ReadOptions::getSection()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 9.3222
c 0
b 0
f 0
cc 5
nc 8
nop 0
1
<?php
2
3
/*
4
 * This file is part of the SexyField package.
5
 *
6
 * (c) Dion Snoeijen <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare (strict_types = 1);
13
14
namespace Tardigrades\SectionField\Service;
15
16
use Assert\Assertion;
17
use Assert\AssertionFailedException;
18
use Assert\InvalidArgumentException;
19
use PHPUnit\Framework\AssertionFailedError;
20
use Tardigrades\SectionField\ValueObject\Slug;
21
use Tardigrades\SectionField\ValueObject\After;
22
use Tardigrades\SectionField\ValueObject\Before;
23
use Tardigrades\SectionField\ValueObject\FullyQualifiedClassName;
24
use Tardigrades\SectionField\ValueObject\Handle;
25
use Tardigrades\SectionField\ValueObject\Id;
26
use Tardigrades\SectionField\ValueObject\Limit;
27
use Tardigrades\SectionField\ValueObject\Offset;
28
use Tardigrades\SectionField\ValueObject\OrderBy;
29
use Tardigrades\SectionField\ValueObject\Search;
30
use Tardigrades\SectionField\ValueObject\Sort;
31
32
class ReadOptions implements ReadOptionsInterface
33
{
34
    /** Read options that are relevant for all readers */
35
    const ID = 'id';
36
    const SLUG = 'slug';
37
    const SECTION = 'section';
38
    const SECTION_ID = 'sectionId';
39
    const LIMIT = 'limit';
40
    const OFFSET = 'offset';
41
    const ORDER_BY = 'orderBy';
42
    const SORT = 'sort';
43
    const BEFORE = 'before';
44
    const AFTER = 'after';
45
    const LOCALE_ENABLED = 'localeEnabled';
46
    const LOCALE = 'locale';
47
    const SEARCH = 'search';
48
    const FIELD = 'field';
49
    const JOIN = 'join';
50
51
    /**
52
     * @var string If you know in advance what fields you are going to need
53
     * use the fetchFields option. That way a custom DQL query will be built
54
     * and greatly improve performance because we are bypassing the default
55
     * LAZY_LOADING setup of doctrine.
56
     *
57
     * A string like that should be comma separated. If you need fields that are
58
     * in a relationship, add the entity property name that would return the relationship.
59
     * title,subTitle,someRelation,someRelationTitle
60
     */
61
    const FETCH_FIELDS = 'fetchFields';
62
63
    /** @var array */
64
    protected $options;
65
66
    private function __construct(
67
        array $options
68
    ) {
69
        $valid = false;
70
        if (is_array($options[ReadOptions::SECTION])) {
71
            $valid = true;
72
        }
73
74
        if (is_string($options[ReadOptions::SECTION])) {
75
            $valid = true;
76
        }
77
78
        if ($options[ReadOptions::SECTION] instanceof FullyQualifiedClassName) {
79
            $valid = true;
80
        }
81
82
        if (!$valid) {
83
            throw new InvalidArgumentException(
84
                'The section is not of a valid type',
85
                400,
86
                null,
87
                $options[ReadOptions::SECTION]
88
            );
89
        }
90
91
        $this->options = $options;
92
    }
93
94
    public function getSection(): array
95
    {
96
        $sectionEntities = [];
97
98
        if ($this->options[ReadOptions::SECTION] instanceof FullyQualifiedClassName) {
99
            $sectionEntities = [$this->options[ReadOptions::SECTION]];
100
        }
101
102
        if (is_string($this->options[ReadOptions::SECTION])) {
103
            $sectionEntities = [FullyQualifiedClassName::fromString($this->options[ReadOptions::SECTION])];
104
        }
105
106
        if (is_array($this->options[ReadOptions::SECTION])) {
107
            foreach ($this->options[ReadOptions::SECTION] as $section) {
108
                $sectionEntities[] = FullyQualifiedClassName::fromString((string) $section);
109
            }
110
        }
111
112
        return $sectionEntities;
113
    }
114
115
    public function getSectionId(): ?Id
116
    {
117
        try {
118
            Assertion::keyIsset(
119
                $this->options,
120
                ReadOptions::SECTION_ID,
121
                'The sectionId is not set'
122
            );
123
            Assertion::integerish(
124
                $this->options[ReadOptions::SECTION_ID],
125
                'The sectionId needs to be an integer'
126
            );
127
        } catch (AssertionFailedException $exception) {
128
            return null;
129
        }
130
131
        return Id::fromInt($this->options[ReadOptions::SECTION_ID]);
132
    }
133
134
    public function getOffset(): ?Offset
135
    {
136
        try {
137
            Assertion::keyIsset(
138
                $this->options,
139
                ReadOptions::OFFSET,
140
                'The offset is not set'
141
            );
142
            Assertion::integerish(
143
                $this->options[ReadOptions::OFFSET],
144
                'The offset needs to be an integer.'
145
            );
146
        } catch (AssertionFailedException $exception) {
147
            return null;
148
        }
149
150
        return Offset::fromInt($this->options[ReadOptions::OFFSET]);
151
    }
152
153
    public function getLimit(): ?Limit
154
    {
155
        try {
156
            Assertion::keyIsset(
157
                $this->options,
158
                ReadOptions::LIMIT,
159
                'The limit is not set'
160
            );
161
            Assertion::integerish(
162
                $this->options[ReadOptions::LIMIT],
163
                'The limit needs to be an integer.'
164
            );
165
        } catch (AssertionFailedException $exception) {
166
            return null;
167
        }
168
169
        return Limit::fromInt($this->options[ReadOptions::LIMIT]);
170
    }
171
172
    public function getOrderBy(): ?OrderBy
173
    {
174
        try {
175
            Assertion::keyIsset(
176
                $this->options,
177
                ReadOptions::ORDER_BY,
178
                'orderBy is not set'
179
            );
180
            Assertion::isArray(
181
                $this->options[ReadOptions::ORDER_BY],
182
                'Order by needs to be an array. Example: (["some" => "ASC"])'
183
            );
184
            $handle = Handle::fromString(key($this->options[ReadOptions::ORDER_BY]));
185
            $sort = Sort::fromString(array_values($this->options[ReadOptions::ORDER_BY])[0]);
186
            $orderBy = OrderBy::fromHandleAndSort($handle, $sort);
187
        } catch (AssertionFailedException $exception) {
188
            return null;
189
        }
190
191
        return $orderBy;
192
    }
193
194
    public function getBefore(): ?Before
195
    {
196
        try {
197
            Assertion::keyIsset($this->options, ReadOptions::BEFORE, 'Before is not defined');
198
            Assertion::string($this->options[ReadOptions::BEFORE]);
199
        } catch (AssertionFailedException $exception) {
200
            return null;
201
        }
202
203
        return Before::fromString($this->options[ReadOptions::BEFORE]);
204
    }
205
206
    public function getAfter(): ?After
207
    {
208
        try {
209
            Assertion::keyIsset($this->options, ReadOptions::AFTER, 'After is not defined');
210
            Assertion::string($this->options[ReadOptions::AFTER]);
211
        } catch (AssertionFailedException $exception) {
212
            return null;
213
        }
214
215
        return After::fromString($this->options[ReadOptions::AFTER]);
216
    }
217
218
    public function getLocaleEnabled(): ?bool
219
    {
220
        try {
221
            Assertion::keyIsset($this->options, ReadOptions::LOCALE_ENABLED, 'localeEnabled is not set');
222
            Assertion::boolean($this->options[ReadOptions::LOCALE_ENABLED]);
223
        } catch (AssertionFailedException $exception) {
224
            return null;
225
        }
226
227
        return (bool) $this->options[ReadOptions::LOCALE_ENABLED];
228
    }
229
230
    public function getLocale(): ?string
231
    {
232
        try {
233
            Assertion::keyIsset($this->options, ReadOptions::LOCALE, 'No locale defined');
234
            Assertion::string($this->options[ReadOptions::LOCALE], 'Locale is supposed to be a string like en_EN');
235
        } catch (AssertionFailedException $exception) {
236
            return null;
237
        }
238
239
        return (string) $this->options[ReadOptions::LOCALE];
240
    }
241
242
    public function getSearch(): ?Search
243
    {
244
        try {
245
            Assertion::keyIsset($this->options, ReadOptions::SEARCH, 'No search defined');
246
            Assertion::string($this->options[ReadOptions::SEARCH], 'The search term must be a string');
247
        } catch (AssertionFailedException $exception) {
248
            return null;
249
        }
250
251
        return Search::fromString($this->options[ReadOptions::SEARCH]);
252
    }
253
254
    public function getField(): ?array
255
    {
256
        try {
257
            Assertion::keyExists(
258
                $this->options,
259
                ReadOptions::FIELD,
260
                'The key field should exist'
261
            );
262
            Assertion::notEmpty(
263
                $this->options[ReadOptions::FIELD],
264
                'The field option must contain something.'
265
            );
266
            Assertion::isArray(
267
                $this->options[ReadOptions::FIELD],
268
                'The field option must be an array. "fieldHandle" => "value"'
269
            );
270
        } catch (AssertionFailedException $exception) {
271
            return null;
272
        }
273
274
        return $this->options[ReadOptions::FIELD];
275
    }
276
277
    public function getJoin(): ?array
278
    {
279
        try {
280
            Assertion::keyExists($this->options, ReadOptions::JOIN, 'The key join should exist');
281
            Assertion::notEmpty(
282
                $this->options[ReadOptions::JOIN],
283
                'The join option must contain something.'
284
            );
285
            Assertion::isArray(
286
                $this->options[ReadOptions::JOIN],
287
                'The join option must be an array. "fieldHandle" => "value"'
288
            );
289
        } catch (AssertionFailedException $exception) {
290
            return null;
291
        }
292
293
        return $this->options[ReadOptions::JOIN];
294
    }
295
296
    public function getId(): ?Id
297
    {
298
        try {
299
            Assertion::keyIsset($this->options, ReadOptions::ID, 'This id is not set');
300
            Assertion::digit($this->options[ReadOptions::ID], 'The id is not numeric');
301
        } catch (AssertionFailedException $exception) {
302
            return null;
303
        }
304
305
        return Id::fromInt($this->options[ReadOptions::ID]);
306
    }
307
308
    public function getSlug(): ?Slug
309
    {
310
        try {
311
            Assertion::keyIsset($this->options, ReadOptions::SLUG, 'The slug is not set');
312
313
            // There is a possibility the read options are built with a value object,
314
            // added flexibility by converting value to slug first.
315
            if ($this->options[ReadOptions::SLUG] instanceof Slug) {
316
                Assertion::string((string) $this->options[ReadOptions::SLUG], 'The slug is supposed to be a string');
317
            } else {
318
                Assertion::string($this->options[ReadOptions::SLUG], 'The slug is supposed to be a string');
319
            }
320
321
            return Slug::fromString((string) $this->options[ReadOptions::SLUG]);
322
        } catch (AssertionFailedException $exception) {
323
            return null;
324
        }
325
    }
326
327
    public function getFetchFields(): ?array
328
    {
329
        try {
330
            Assertion::keyIsset($this->options, ReadOptions::FETCH_FIELDS, 'No fetch fields');
331
            Assertion::notEmpty(
332
                $this->options[ReadOptions::FETCH_FIELDS],
333
                'The fetch fields are empty.'
334
            );
335
            Assertion::string($this->options[ReadOptions::FETCH_FIELDS], 'Fetch fields must be a string');
336
        } catch (AssertionFailedException $exception) {
337
            return null;
338
        }
339
340
        return explode(',', $this->options[ReadOptions::FETCH_FIELDS]);
341
    }
342
343
    public static function fromArray(array $options): ReadOptionsInterface
344
    {
345
        return new static($options);
346
    }
347
348
    public function toArray(): array
349
    {
350
        return $this->options;
351
    }
352
}
353