FormResponse::requestPage()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Riclep\StoryblokForms;
4
5
use Illuminate\Http\Request;
6
use Illuminate\Http\UploadedFile;
7
use Illuminate\Support\Arr;
8
use Illuminate\Support\Facades\Validator;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Riclep\StoryblokForms\Validator. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
9
use JsonException;
10
use Riclep\Storyblok\StoryblokFacade as StoryBlok;
11
12
class FormResponse
13
{
14
	// TODO - pass extra data - imagine a staff contact form wrapped in a component where they select the email address this instance should go to
15
16
17
	/**
18
	 * @var Request
19
	 */
20
	public Request $request;
21
22
	/**
23
	 * The Storyblok page for this form
24
	 *
25
	 * @var
26
	 */
27
	protected $page;
28
29
	/**
30
	 * You’ll most likely want to extend this class to add your own functionality. The FormResponse
31
	 * is used when you’ve submitted your form for validation and further processing. It will
32
	 * output a nested array of fields and the value inputted / selected.
33
	 *
34
	 * @param Request $request
35
	 */
36
	public function __construct(Request $request)
37
	{
38
		// convert JSON response to same format as standard HTML forms
39
		if ($request->isJson()) {
40
			$request->replace(Arr::undot($request->all()));
41
		}
42
43
		$this->request = $request;
44
45
		$this->requestPage();
46
	}
47
48
49
	/**
50
	 * The FormResponse needs to load the form’s page from Storyblok so it can know
51
	 * all the fields and inputs to expect. By default we pass the page’s slug
52
	 * with the request so we know what to request
53
	 *
54
	 * @return void
55
	 */
56
	protected function requestPage(): void
57
	{
58
		$this->page = Storyblok::read($this->request->input('_slug'));
59
	}
60
61
	/**
62
	 * The Field that holds the form on the Page from Storyblok
63
	 *
64
	 */
65
	protected function form()
66
	{
67
		return $this->page->form;
68
	}
69
70
71
	/**
72
	 * Creates a Laravel Validator taking the request and the rules and messages from the Storyblok
73
	 * form description. Failing validation redirects the user back to the form / returns a JSON
74
	 * errorbag if you’re posting asynchronously
75
	 *
76
	 * @return void
77
	 */
78
	public function validate(): void
79
	{
80
		Validator::make($this->request->all(), $this->form()->validationRules(), $this->form()->errorMessages())->validate();
81
	}
82
83
84
	/**
85
	 * Get the validation rules for this form. It’ll load the ones defined in Storyblok but you can
86
	 * override or extend them as needed - just return any valid rules.
87
	 *
88
	 * @return mixed
89
	 */
90
	public function validationRules(): mixed
91
	{
92
		return $this->form()->validationRules();
93
	}
94
95
	/**
96
	 * Returns the fields and their innput
97
	 *
98
	 * @return mixed
99
	 */
100
	public function fields(): mixed
101
	{
102
		return $this->responses();
103
	}
104
105
	/**
106
	 * Converts the fields and their input to JSON
107
	 *
108
	 * @return false|string
109
	 * @throws JsonException
110
	 */
111
	public function json(): bool|string
112
	{
113
		return json_encode($this->fields(), JSON_THROW_ON_ERROR);
114
	}
115
116
	/**
117
	 * Loops over all the fields and passes the input into them so we can build
118
	 * a nested array of every field and it’s inputted / selected values
119
	 *
120
	 * @return array
121
	 */
122
	protected function responses(): array
123
	{
124
		$input = $this->request->except(['_token', '_slug']);
125
126
		return $this->form()->fields->map(function ($field) use ($input) {
127
128
			// Handle empty radio buttons sending nothing in POST request
129
			//if ($field instanceof \Riclep\StoryblokForms\Blocks\LsfRadioButton) {
130
				if (!array_key_exists($field->name, $input)) {
131
					$input[$field->name] = null;
132
				}
133
			//}
134
135
			return $field->response($input[$field->name]);
136
		})->keyBy('name')->toArray();
137
	}
138
139
140
	/**
141
	 * Flattens the response returning an array of field responses
142
	 *
143
	 * @return array
144
	 */
145
	public function flatten(): array
146
	{
147
		return Arr::flatten($this->fields());
148
	}
149
150
151
	/**
152
	 * Find any uploaded files so we’re easily able to handle them
153
	 *
154
	 * @return array
155
	 */
156
	public function files(): array
157
	{
158
		return array_values(array_filter($this->flatten(), function ($response) {
159
			return $response instanceof UploadedFile;
160
		}));
161
	}
162
}