Passed
Push — master ( 147f66...7138a8 )
by Richard
17:47 queued 12:18
created

FieldFactory::classField()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 8
c 1
b 0
f 0
nc 4
nop 3
dl 0
loc 19
rs 10
1
<?php
2
3
namespace Riclep\Storyblok;
4
5
use Illuminate\Support\Str;
6
use Riclep\Storyblok\Fields\Asset;
7
use Riclep\Storyblok\Fields\Image;
8
use Riclep\Storyblok\Fields\MultiAsset;
9
use Riclep\Storyblok\Fields\RichText;
10
use Riclep\Storyblok\Fields\Table;
11
12
class FieldFactory
13
{
14
	/**
15
	 * Works out what class should be used for the given block’s content
16
	 *
17
	 * @param $block
18
	 * @param $field
19
	 * @param $key
20
	 * @return \Illuminate\Support\Collection|mixed|Asset|Image|MultiAsset|RichText|Table
21
	 */
22
	public function build($block, $field, $key): mixed
23
	{
24
		$isClassField = $this->classField($block, $field, $key);
25
26
		if ($isClassField) {
27
			return $isClassField;
28
		}
29
30
		// single item relations
31
		if (Str::isUuid($field) && ($block->_autoResolveRelations || in_array($key, $block->_resolveRelations, true) || array_key_exists($key, $block->_resolveRelations))) {
32
33
			if (array_key_exists($key, $block->_resolveRelations)) {
34
				return $block->getRelation(new RequestStory(), $field, $block->_resolveRelations[$key]);
35
			}
36
37
			return $block->getRelation(new RequestStory(), $field);
38
		}
39
40
		// complex fields
41
		if (is_array($field) && !empty($field)) {
42
			return $this->arrayField($block, $field, $key);
43
		}
44
45
		// legacy and string image fields
46
		if ($this->isStringImageField($field)) {
47
			return new Image($field, $block);
48
		}
49
50
		// strings or anything else - do nothing
51
		return $field;
52
	}
53
54
	/**
55
	 * @param $block
56
	 * @param $field
57
	 * @param $key
58
	 * @return mixed
59
	 */
60
	protected function classField($block, $field, $key): mixed
61
	{
62
		// does the Block assign any $_casts? This is key (field) => value (class)
63
		if (array_key_exists($key, $block->getCasts())) {
64
			$casts = $block->getCasts();
65
			return new $casts[$key]($field, $block);
66
		}
67
68
		// find Fields specific to this Block matching: BlockNameFieldName
69
		if ($class = $block->getChildClassName('Field', $block->component() . '_' . $key)) {
70
			return new $class($field, $block);
71
		}
72
73
		// auto-match Field classes
74
		if ($class = $block->getChildClassName('Field', $key)) {
75
			return new $class($field, $block);
76
		}
77
78
		return false;
79
	}
80
81
	/**
82
	 * If given an array field we need more processing to determine the class
83
	 *
84
	 * @param $block
85
	 * @param $field
86
	 * @param $key
87
	 * @return \Illuminate\Support\Collection|mixed|Asset|Image|MultiAsset|RichText|Table
88
	 */
89
	protected function arrayField($block, $field, $key): mixed
90
	{
91
		// match link fields
92
		if (array_key_exists('linktype', $field)) {
93
			$class = 'Riclep\Storyblok\Fields\\' . Str::studly($field['linktype']) . 'Link';
94
95
			return new $class($field, $block);
96
		}
97
98
		// match rich-text fields
99
		if (array_key_exists('type', $field) && $field['type'] === 'doc') {
100
			return new RichText($field, $block);
101
		}
102
103
		// match asset fields - detecting raster images
104
		if (array_key_exists('fieldtype', $field) && $field['fieldtype'] === 'asset') {
105
			// legacy and string image fields
106
			if($this->isStringImageField($field['filename'])) {
107
				return new Image($field, $block);
108
			}
109
110
			return new Asset($field, $block);
111
		}
112
113
		// match table fields
114
		if (array_key_exists('fieldtype', $field) && $field['fieldtype'] === 'table') {
115
			return new Table($field, $block);
116
		}
117
118
		if (array_key_exists(0, $field)) {
119
			return $this->relationField($block, $field, $key);
120
		}
121
122
		// just return the array
123
		return $field;
124
	}
125
126
	protected function relationField($block, $field, $key) {
127
		// it’s an array of relations - request them if we’re auto or manual resolving
128
		if (Str::isUuid($field[0])) {
129
			if ($block->_autoResolveRelations || array_key_exists($key, $block->_resolveRelations) || in_array($key, $block->_resolveRelations, true)) {
130
131
				// they’re passing a custom class
132
				if (array_key_exists($key, $block->_resolveRelations)) {
133
					$relations = collect($field)->transform(fn($relation) => $block->getRelation(new RequestStory(), $relation, $block->_resolveRelations[$key]));
134
				} else {
135
					$relations = collect($field)->transform(fn($relation) => $block->getRelation(new RequestStory(), $relation));
136
				}
137
138
				if ($block->_filterRelations) {
139
					$relations = $relations->filter();
140
				}
141
142
				return $relations;
143
			}
144
		}
145
146
		// has child items - single option, multi option and Blocks fields
147
		if (is_array($field[0])) {
148
			// resolved relationships - entire story is returned, we just want the content and a few meta items
149
			if (array_key_exists('content', $field[0])) {
150
				return collect($field)->transform(function ($relation) use ($block) {
151
					$class = $block->getChildClassName('Block', $relation['content']['component']);
152
					$relationClass = new $class($relation['content'], $block);
153
154
					$relationClass->addMeta([
155
						'name' => $relation['name'],
156
						'published_at' => $relation['published_at'],
157
						'full_slug' => $relation['full_slug'],
158
					]);
159
160
					return $relationClass;
161
				});
162
			}
163
164
			// this field holds blocks!
165
			if (array_key_exists('component', $field[0])) {
166
				return collect($field)->transform(function ($childBlock) use ($block) {
167
					$class = $block->getChildClassName('Block', $childBlock['component']);
168
169
					return new $class($childBlock, $block);
170
				});
171
			}
172
173
			// multi assets
174
			if (array_key_exists('filename', $field[0])) {
175
				return new MultiAsset($field, $block);
176
			}
177
		}
178
	}
179
180
	/**
181
	 * Check if given string is a string image field
182
	 *
183
	 * @param  $filename
184
	 * @return boolean
185
	 */
186
	public function isStringImageField($filename): bool
187
	{
188
		$allowed_extentions = ['.jpg', '.jpeg', '.png', '.gif', '.webp'];
189
190
		return is_string($filename) && Str::of($filename)->lower()->endsWith($allowed_extentions);
191
	}
192
}