Completed
Push — master ( 36b1e4...ae0e44 )
by Nekrasov
03:18
created

getWidgetNameWithCustomNamespace()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Arrilot\Widgets\Factories;
4
5
use Arrilot\Widgets\AbstractWidget;
6
use Arrilot\Widgets\Contracts\ApplicationWrapperContract;
7
use Arrilot\Widgets\Misc\EncryptException;
8
use Arrilot\Widgets\Misc\InvalidWidgetClassException;
9
use Arrilot\Widgets\Misc\ViewExpressionTrait;
10
use Arrilot\Widgets\WidgetId;
11
use Illuminate\Support\Str;
12
13
abstract class AbstractWidgetFactory
14
{
15
    use ViewExpressionTrait;
16
17
    /**
18
     * Widget object to work with.
19
     *
20
     * @var AbstractWidget
21
     */
22
    protected $widget;
23
24
    /**
25
     * Widget configuration array.
26
     *
27
     * @var array
28
     */
29
    protected $widgetConfig;
30
31
    /**
32
     * The name of the widget being called.
33
     *
34
     * @var string
35
     */
36
    public $widgetName;
37
38
    /**
39
     * Custom widget namespace of the widget being called if is set.
40
     *
41
     * @var string|null
42
     */
43
    public $customWidgetNamespace;
44
45
    /**
46
     * Array of widget parameters excluding the first one (config).
47
     *
48
     * @var array
49
     */
50
    public $widgetParams;
51
52
    /**
53
     * Array of widget parameters including the first one (config).
54
     *
55
     * @var array
56
     */
57
    public $widgetFullParams;
58
59
    /**
60
     * Laravel application wrapper for better testability.
61
     *
62
     * @var ApplicationWrapperContract;
63
     */
64
    public $app;
65
66
    /**
67
     * Another factory that produces some javascript.
68
     *
69
     * @var JavascriptFactory
70
     */
71
    protected $javascriptFactory;
72
73
    /**
74
     * The flag for not wrapping content in a special container.
75
     *
76
     * @var bool
77
     */
78
    public static $skipWidgetContainer = false;
79
80
    /**
81
     * The flag for not wrapping content in a special container.
82
     *
83
     * @var bool
84
     */
85
    public static $allowOnlyWidgetsWithDisabledEncryption = false;
86
87
    /**
88
     * Constructor.
89
     *
90
     * @param ApplicationWrapperContract $app
91
     */
92
    public function __construct(ApplicationWrapperContract $app)
93
    {
94
        $this->app = $app;
95
96
        $this->javascriptFactory = new JavascriptFactory($this);
97
    }
98
99
    /**
100
     * Magic method that catches all widget calls.
101
     *
102
     * @param string $widgetName
103
     * @param array  $params
104
     *
105
     * @return mixed
106
     */
107
    public function __call($widgetName, array $params = [])
108
    {
109
        array_unshift($params, $widgetName);
110
111
        return call_user_func_array([$this, 'run'], $params);
112
    }
113
114
    /**
115
     * Set class properties and instantiate a widget object.
116
     *
117
     * @param $params
118
     *
119
     * @throws InvalidWidgetClassException
120
     * @throws EncryptException
121
     */
122
    protected function instantiateWidget(array $params = [])
123
    {
124
        WidgetId::increment();
125
126
        $str = array_shift($params);
127
128
        if (preg_match('#^(.*?)::(.*?)$#', $str, $m)) {
129
            $rootNamespace = $this->app->get('arrilot.widget-namespaces')->getNamespace($m[1]);
130
            $this->customWidgetNamespace = $m[1];
131
            $str = $m[2];
132
        } else {
133
            $this->customWidgetNamespace = null;
134
        }
135
        
136
        $this->widgetName = $this->parseFullWidgetNameFromString($str);
137
        $this->widgetFullParams = $params;
138
        $this->widgetConfig = (array) array_shift($params);
139
        $this->widgetParams = $params;
140
141
        if (!isset($rootNamespace)) {
142
            $rootNamespace = $this->app->config('laravel-widgets.default_namespace', $this->app->getNamespace().'Widgets');
143
        }
144
145
        $fqcn = $rootNamespace.'\\'.$this->widgetName;
146
        $widgetClass = class_exists($fqcn) ? $fqcn : $this->widgetName;
147
148
        if (!class_exists($widgetClass)) {
149
            throw new InvalidWidgetClassException('Class "'.$widgetClass.'" does not exist');
150
        }
151
152
        if (!is_subclass_of($widgetClass, 'Arrilot\Widgets\AbstractWidget')) {
153
            throw new InvalidWidgetClassException('Class "'.$widgetClass.'" must extend "Arrilot\Widgets\AbstractWidget" class');
154
        }
155
156
        $this->widget = $this->app->make($widgetClass, ['config' => $this->widgetConfig]);
157
158
        if (static::$allowOnlyWidgetsWithDisabledEncryption && $this->widget->encryptParams) {
159
            throw new EncryptException('Widget "'.$widgetClass.'" was not called properly');
160
        }
161
    }
162
163
    /**
164
     * Convert stuff like 'profile.feedWidget' to 'Profile\FeedWidget'.
165
     *
166
     * @param $widgetName
167
     *
168
     * @return string
169
     */
170
    protected function parseFullWidgetNameFromString($widgetName)
171
    {
172
        return Str::studly(str_replace('.', '\\_', $widgetName));
173
    }
174
175
    /**
176
     * Wrap the given content in a container if it's not an ajax call.
177
     *
178
     * @param $content
179
     *
180
     * @return string
181
     */
182
    protected function wrapContentInContainer($content)
183
    {
184
        if (self::$skipWidgetContainer) {
185
            return $content;
186
        }
187
188
        $container = $this->widget->container();
189
        if (empty($container['element'])) {
190
            $container['element'] = 'div';
191
        }
192
193
        return '<'.$container['element'].' id="'.$this->javascriptFactory->getContainerId().'" '.$container['attributes'].'>'.$content.'</'.$container['element'].'>';
194
    }
195
196
    /**
197
     * Encrypt widget params to be transported via HTTP.
198
     *
199
     * @param string $params
200
     *
201
     * @return string
202
     */
203
    public function encryptWidgetParams($params)
204
    {
205
        return $this->app->make('encrypter')->encrypt($params);
206
    }
207
208
    /**
209
     * Decrypt widget params that were transported via HTTP.
210
     *
211
     * @param string $params
212
     *
213
     * @return string
214
     */
215
    public function decryptWidgetParams($params)
216
    {
217
        return $this->app->make('encrypter')->decrypt($params);
218
    }
219
220
    /**
221
     * Get current widget name with optional custom widget namespace.
222
     * 
223
     * @return string
224
     */
225
    public function getWidgetNameWithCustomNamespace()
226
    {
227
        return $this->customWidgetNamespace 
228
            ? $this->customWidgetNamespace . '::' . $this->widgetName
229
            : $this->widgetName;
230
    }
231
}
232