Page   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 202
Duplicated Lines 0 %

Importance

Changes 17
Bugs 0 Features 0
Metric Value
wmc 19
eloc 45
c 17
b 0
f 0
dl 0
loc 202
rs 10

13 Methods

Rating   Name   Duplication   Size   Complexity  
A createBlock() 0 5 1
A slug() 0 3 1
A updatedAt() 0 3 1
A views() 0 7 1
A publishedAt() 0 3 1
A block() 0 3 1
A story() 0 3 1
A __get() 0 11 3
A tags() 0 7 2
A hasTag() 0 3 1
A render() 0 6 2
A preprocess() 0 9 1
A __construct() 0 11 3
1
<?php
2
3
4
namespace Riclep\Storyblok;
5
6
use Carbon\Carbon;
7
use Illuminate\Support\Str;
8
use Illuminate\View\View;
9
use Riclep\Storyblok\Exceptions\UnableToRenderException;
10
use Riclep\Storyblok\Traits\HasChildClasses;
11
use Riclep\Storyblok\Traits\HasMeta;
12
use Riclep\Storyblok\Traits\SchemaOrg;
13
14
class Page
15
{
16
	use HasChildClasses;
17
	use HasMeta;
18
	use SchemaOrg;
19
20
	/**
21
	 * @var string[] this is the root of the path so includes the page
22
	 */
23
	public array $_componentPath = ['page'];
24
25
	/**
26
	 * @var Block root Block of the page’s content
27
	 */
28
	private Block $block;
29
30
	/**
31
	 * @var array the JSON decoded array from Storyblok
32
	 */
33
	private array $story;
34
35
	/**
36
	 * @var array holds all the fields indexed by UUID for the JS live bridge
37
	 */
38
	public array $liveContent = [];
39
40
	/**
41
	 * Page constructor.
42
	 * @param $story
43
	 */
44
	public function __construct($story) {
45
		$this->story = $story;
46
47
		$this->preprocess();
48
49
		$this->block = $this->createBlock($this->story['content']);
50
51
		// run automatic traits - methods matching initTraitClassName()
52
		foreach (class_uses_recursive($this) as $trait) {
53
			if (method_exists($this, $method = 'init' . class_basename($trait))) {
54
				$this->{$method}();
55
			}
56
		}
57
	}
58
59
	/**
60
	 * Returns a view populated with the story’s content. Additional data can
61
	 * be passed in using an associative array
62
	 *
63
	 * @param array $additionalContent
64
	 * @return View
65
	 * @throws UnableToRenderException
66
	 */
67
	public function render($additionalContent = []): View
68
	{
69
		try {
70
			return view()->first($this->views(), array_merge(['story' => $this], $additionalContent));
71
		} catch (\Exception $exception) {
72
			throw new UnableToRenderException('None of the views in the given array exist.', $this);
73
		}
74
	}
75
76
	/**
77
	 * Returns a list of possible arrays for this page based on the Storyblok
78
	 * contentType component’s name
79
	 *
80
	 * @return array
81
	 */
82
	public function views(): array
83
	{
84
		$views = array_map(function($path) {
85
			return config('storyblok.view_path') . 'pages.' . $path;
86
		}, $this->block()->_componentPath);
87
88
		return array_reverse($views);
89
	}
90
91
	/**
92
	 * Returns the story for this Page
93
	 *
94
	 * @return array
95
	 */
96
	public function story(): array
97
	{
98
		return $this->story;
99
	}
100
101
	/**
102
	 * Return a lovely Carbon object of the first published date
103
	 *
104
	 * @return Carbon
105
	 */
106
	public function publishedAt(): Carbon
107
	{
108
		return Carbon::parse($this->story['first_published_at']);
109
	}
110
111
	/**
112
	 * A Carbon object for the most recent publish date
113
	 *
114
	 * @return Carbon
115
	 */
116
	public function updatedAt(): Carbon
117
	{
118
		return Carbon::parse($this->story['published_at']);
119
	}
120
121
	/**
122
	 * Returns the full slug for the page
123
	 *
124
	 * @return string
125
	 */
126
	public function slug(): string
127
	{
128
		return $this->story['full_slug'];
129
	}
130
131
	/**
132
	 * Returns all the tags, sorting them if so desired
133
	 *
134
	 * @param bool $alphabetical
135
	 * @return mixed
136
	 */
137
	public function tags(bool $alphabetical = false): mixed
138
	{
139
		if ($alphabetical) {
140
			sort($this->story['tag_list']);
141
		}
142
143
		return $this->story['tag_list'];
144
	}
145
146
	/**
147
	 * Checks if this page has the matching tag
148
	 *
149
	 * @param $tag
150
	 * @return bool
151
	 */
152
	public function hasTag($tag): bool
153
	{
154
		return in_array($tag, $this->tags());
155
	}
156
157
	/**
158
	 * Returns the page’s contentType Block - this is the component type
159
	 * used for the page in Storyblok
160
	 *
161
	 * @return Block
162
	 */
163
	public function block(): Block
164
	{
165
		return $this->block;
166
	}
167
168
	/**
169
	 * Magic getter to return fields from the contentType block for this page
170
	 * without having to reach into the page.
171
	 *
172
	 * @param $name
173
	 * @return bool|string
174
	 */
175
	public function __get($name) {
176
		// check for accessor on the root block
177
		$accessor = 'get' . Str::studly($name) . 'Attribute';
178
179
		if (method_exists($this->block(), $accessor)) {
180
			return $this->block()->$accessor();
181
		}
182
183
		// check for attribute on the root block
184
		if ($this->block()->has($name)) {
185
			return $this->block()->{$name};
186
		}
187
	}
188
189
	/**
190
	 * Does a bit of housekeeping before processing the data
191
	 * from Storyblok any further
192
	 */
193
	protected function preprocess(): void
194
	{
195
		$this->addMeta([
196
			'_uid' => $this->story['uuid'],
197
			'name' => $this->story['name'],
198
			'tags' => $this->story['tag_list'],
199
			'slug' => $this->story['full_slug'],
200
			'published_at' => Carbon::parse($this->story['first_published_at']),
201
			'updated_at' => Carbon::parse($this->story['published_at']),
202
		]);
203
	}
204
205
	/**
206
	 * Creates the Block for the page’s contentType component
207
	 *
208
	 * @param $content
209
	 * @return mixed
210
	 */
211
	private function createBlock($content): mixed
212
	{
213
		$class = $this->getChildClassName('Block', $content['component']);
214
215
		return new $class($content, $this);
216
	}
217
}