Completed
Push — master ( f54537...394c45 )
by Mihail
02:09
created

FieldSelector::findFieldLayer()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 19
rs 9.2
cc 4
eloc 14
nc 4
nop 2
1
<?php
2
3
namespace Ffcms\Core\Helper\HTML\Form;
4
5
6
use Ffcms\Core\App;
7
use Ffcms\Core\Arch\Model;
8
use Ffcms\Core\Exception\SyntaxException;
9
use Ffcms\Core\Helper\HTML\System\NativeGenerator;
10
use Ffcms\Core\Helper\Type\Arr;
11
use Ffcms\Core\Helper\Type\Str;
12
13
/**
14
 * Class FieldSelector. Form field builder instance.
15
 * @package Ffcms\Core\Helper\HTML\Form
16
 * @method text(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
17
 * @method password(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
18
 * @method hidden(string $name, ?array $properties = null)
19
 * @method select(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
20
 * @method checkbox(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
21
 * @method email(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
22
 * @method textarea(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
23
 * @method checkboxes(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
24
 * @method captcha(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
25
 * @method file(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
26
 * @method div(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
27
 * @method radio(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
28
 * @method multiselect(string $name, ?array $properties = null, ?string $helper = null, ?string $layerFile = null)
29
 */
30
class FieldSelector extends NativeGenerator
31
{
32
    /** @var Model */
33
    private $model;
34
    /** @var array */
35
    private $layers;
36
37
    /**
38
     * FieldSelector constructor.
39
     * @param Model $model
40
     * @param array $defaultLayers
41
     */
42
    public function __construct(Model $model, array $defaultLayers = [])
43
    {
44
        $this->model = $model;
45
        $this->layers = $defaultLayers;
46
    }
47
48
    /**
49
     * @param string $field
50
     * @param array|null $arguments
51
     * @return string|null
52
     */
53
    public function __call(string $field, ?array $arguments = null): ?string
54
    {
55
        if ($arguments === null || count($arguments) < 1)
56
            return null;
57
58
        // get named arguments from passed array
59
        $name = (string)$arguments[0];
60
        $rootName = $name;
61
        // set root element name if array dot-nested notation found
62
        if (Str::contains('.', $name))
63
            $rootName = strstr($rootName, '.', true);
64
        // define properties, helper and layer
65
        $properties = null;
66
        $helper = null;
67
        $layer = null;
68
        if (isset($arguments[1]))
69
            $properties = (array)$arguments[1];
70
71
        if (isset($arguments[2]))
72
            $helper = (string)$arguments[2];
73
74
        if (isset($arguments[3]))
75
            $layer = (string)$arguments[3];
76
77
        // check if model has attribute
78
        if (!property_exists($this->model, $rootName)) {
79
            if (App::$Debug)
80
                App::$Debug->addMessage('Field "' . $name . '" (' . $field . ') is not defined in model: [' . get_class($this->model) . ']', 'error');
81
82
            return null;
83
        }
84
85
        // prepare default layer if not passed
86
        $layer = $this->findFieldLayer($field, $layer);
87
        // prepare html attributes, object value
88
        $attr = $this->model->getFormName() . '-' . $rootName;
89
        $label = $this->model->getLabel($name);
90
        $value = $this->model->{$rootName};
91
        // check if dot-nested array used and update attr name
92
        if ($rootName !== $name) {
93
            $nesting = trim(strstr($name, '.'), '.');
94
            $attr .= '-' . Str::replace('.', '-', $nesting);
95
            $value = Arr::getByPath($nesting, $value);
96
        }
97
98
        // initialize form fields constructor and build output dom html value
99
        $constructor = new Constructor($this->model, $this->model->getFormName(), $field);
100
        $elementDOM = $constructor->makeTag($name, $value, $properties);
101
102
        // if item is hidden - return tag without assign of global template
103
        if ($field === 'hidden')
104
            return $elementDOM;
105
106
        // prepare output html
107
        try {
108
            return App::$View->render($layer, [
109
                'name' => $attr,
110
                'label' => $label,
111
                'item' => $elementDOM,
112
                'help' => self::nohtml($helper)
113
            ]);
114
        } catch (SyntaxException $e) {
115
            if (App::$Debug)
116
                App::$Debug->addException($e);
117
            return null;
118
        }
119
    }
120
121
    /**
122
     * Find default layer if not passed direct
123
     * @param null|string $type
124
     * @param null|string $layer
125
     * @return null|string
126
     */
127
    private function findFieldLayer(?string $type = null, ?string $layer = null): ?string
128
    {
129
        if ($layer !== null)
130
            return $layer;
131
132
        switch ($type) {
133
            case 'checkbox':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
134
                $layer = $this->layers['checkbox'];
135
                break;
136
            case 'radio':
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
137
                $layer = $this->layers['radio'];
138
                break;
139
            default:
0 ignored issues
show
Coding Style introduced by
DEFAULT statements must be defined using a colon

As per the PSR-2 coding standard, default statements should not be wrapped in curly braces.

switch ($expr) {
    default: { //wrong
        doSomething();
        break;
    }
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
140
                $layer = $this->layers['base'];
141
                break;
142
        }
143
144
        return $layer;
145
    }
146
}