Completed
Push — master ( 8d0d2d...1142a2 )
by Nekrasov
01:31
created

BladeProvider::registerBitrixDirectives()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 30
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 53
rs 9.5797

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Arrilot\BitrixBlade;
4
5
use Illuminate\Container\Container;
6
use Illuminate\Contracts\View\Factory;
7
8
class BladeProvider
9
{
10
    /**
11
     * Path to a folder view common view can be stored.
12
     *
13
     * @var string
14
     */
15
    protected static $baseViewPath;
16
17
    /**
18
     * Local path to blade cache storage.
19
     *
20
     * @var string
21
     */
22
    protected static $cachePath;
23
24
    /**
25
     * View factory.
26
     *
27
     * @var Factory
28
     */
29
    protected static $viewFactory;
30
31
    /**
32
     * Service container factory.
33
     *
34
     * @var Container
35
     */
36
    protected static $container;
37
38
    /**
39
     * Register blade engine in Bitrix.
40
     *
41
     * @param string $baseViewPath
42
     * @param string $cachePath
43
     */
44
    public static function register($baseViewPath = 'local/views', $cachePath = 'bitrix/cache/blade')
0 ignored issues
show
Coding Style introduced by
register uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
45
    {
46
        static::$baseViewPath = $_SERVER['DOCUMENT_ROOT'].'/'.$baseViewPath;
47
        static::$cachePath = $_SERVER['DOCUMENT_ROOT'].'/'.$cachePath;
48
49
        static::instantiateServiceContainer();
50
        static::instantiateViewFactory();
51
        static::registerBitrixDirectives();
52
53
        global $arCustomTemplateEngines;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
54
        $arCustomTemplateEngines['blade'] = [
55
            'templateExt' => ['blade'],
56
            'function'    => 'renderBladeTemplate',
57
        ];
58
    }
59
60
    /**
61
     * Get view factory.
62
     *
63
     * @return Factory
64
     */
65
    public static function getViewFactory()
66
    {
67
        return static::$viewFactory;
68
    }
69
70
    /**
71
     * @return BladeCompiler
72
     */
73
    public function getCompiler()
74
    {
75
        return static::$container['blade.compiler'];
76
    }
77
78
    /**
79
     * Update paths where blade tries to find additional views.
80
     *
81
     * @param string $templateDir
82
     */
83
    public static function addTemplateFolderToViewPaths($templateDir)
0 ignored issues
show
Coding Style introduced by
addTemplateFolderToViewPaths uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
84
    {
85
        $finder = Container::getInstance()->make('view.finder');
86
87
        $currentPaths = $finder->getPaths();
88
        $newPaths = [$_SERVER['DOCUMENT_ROOT'].$templateDir];
89
90
        // Полностью перезаписывать пути нельзя, иначе вложенные компоненты + include перестанут работать.
91
        $newPaths = array_values(array_unique(array_merge($newPaths, $currentPaths)));
92
        if (!in_array(static::$baseViewPath, $newPaths)) {
93
            $newPaths[] = static::$baseViewPath;
94
        }
95
96
        // Необходимо очистить внутренний кэш ViewFinder-а
97
        // Потому что иначе если в родительском компоненте есть @include('foo'), то при вызове @include('foo') из дочернего,
98
        // он не будет искать foo в дочернем, а сразу подключит foo из родительского компонента
99
        $finder->flush();
100
101
        $finder->setPaths($newPaths);
102
    }
103
104
    /**
105
     * Undo addTemplateFolderToViewPaths
106
     *
107
     * @param string $templateDir
108
     */
109
    public static function removeTemplateFolderFromViewPaths($templateDir)
0 ignored issues
show
Coding Style introduced by
removeTemplateFolderFromViewPaths uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
110
    {
111
        $finder = Container::getInstance()->make('view.finder');
112
        $currentPaths = $finder->getPaths();
113
        $finder->setPaths(array_diff($currentPaths, [$_SERVER['DOCUMENT_ROOT'].$templateDir] ));
114
115
        // Необходимо очистить внутренний кэш ViewFinder-а
116
        // Потому что иначе если в дочернем компоненте есть @include('foo'), то при вызове @include('foo') в родительском
117
        // после подключения дочернего,
118
        // он не будет искать foo в родительском, а сразу подключит foo из дочернего компонента
119
        $finder->flush();
120
    }
121
122
    /**
123
     * Instantiate service container if it's not instantiated yet.
124
     */
125
    protected static function instantiateServiceContainer()
126
    {
127
        $container = Container::getInstance();
128
129
        if (!$container) {
130
            $container = new Container();
131
            Container::setInstance($container);
132
        }
133
134
        static::$container = $container;
135
    }
136
137
    /**
138
     * Instantiate view factory.
139
     */
140
    protected static function instantiateViewFactory()
141
    {
142
        static::createDirIfNotExist(static::$baseViewPath);
143
        static::createDirIfNotExist(static::$cachePath);
144
145
        $viewPaths = [
146
            static::$baseViewPath,
147
        ];
148
        $cache = static::$cachePath;
149
150
        $blade = new Blade($viewPaths, $cache, static::$container);
151
152
        static::$viewFactory = $blade->view();
153
        static::$viewFactory->addExtension('blade', 'blade');
154
    }
155
156
    /**
157
     * Create dir if it does not exist.
158
     *
159
     * @param string $path
160
     */
161
    protected static function createDirIfNotExist($path)
162
    {
163
        if (!file_exists($path)) {
164
            $mask = umask(0);
165
            mkdir($path, 0777, true);
166
            umask($mask);
167
        }
168
    }
169
170
    /**
171
     * Register bitrix directives.
172
     */
173
    protected static function registerBitrixDirectives()
174
    {
175
        $compiler = static::getCompiler();
176
177
        $endIf = function () {
178
            return '<?php endif; ?>';
179
        };
180
181
        $compiler->directive('component', function ($expression) {
182
            $expression = rtrim($expression, ')');
183
            $expression = ltrim($expression, '(');
184
185
            return '<?php $APPLICATION->IncludeComponent('.$expression.'); ?>';
186
        });
187
188
        $compiler->directive('bxComponent', function ($expression) {
189
            $expression = rtrim($expression, ')');
190
            $expression = ltrim($expression, '(');
191
192
            return '<?php $APPLICATION->IncludeComponent('.$expression.'); ?>';
193
        });
194
195
        $compiler->directive('block', function ($expression) {
196
            $expression = rtrim($expression, ')');
197
            $expression = ltrim($expression, '(');
198
199
            return '<?php ob_start(); $__bx_block = ' . $expression . '; ?>';
200
        });
201
202
        $compiler->directive('endblock', function () {
203
            return '<?php $APPLICATION->AddViewContent($__bx_block, ob_get_clean()); ?>';
204
        });
205
206
        $compiler->directive('lang', function ($expression) {
207
            return '<?= Bitrix\Main\Localization\Loc::getMessage('.$expression.') ?>';
208
        });
209
210
        $compiler->directive('auth', function () {
211
            return '<?php if($USER->IsAuthorized()): ?>';
212
        });
213
        $compiler->directive('guest', function () {
214
            return '<?php if(!$USER->IsAuthorized()): ?>';
215
        });
216
        $compiler->directive('admin', function () {
217
            return '<?php if($USER->IsAdmin()): ?>';
218
        });
219
220
        $compiler->directive('endauth', $endIf);
221
        $compiler->directive('endguest', $endIf);
222
        $compiler->directive('endadmin', $endIf);
223
224
        static::registerHermitageDirectives($compiler);
0 ignored issues
show
Bug introduced by
Since registerHermitageDirectives() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of registerHermitageDirectives() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
225
    }
226
227
    /**
228
     * @param BladeCompiler $compiler
229
     */
230
    private static function registerHermitageDirectives($compiler)
231
    {
232
        $simpleDirectives = [
233
            'actionAddForIBlock' => 'addForIBlock',
234
        ];
235 View Code Duplication
        foreach ($simpleDirectives as $directive => $action) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
236
            $compiler->directive($directive, function ($expression) use ($action) {
237
                $expression = rtrim($expression, ')');
238
                $expression = ltrim($expression, '(');
239
                return '<?php \Arrilot\BitrixHermitage\Action::' . $action . '($template, ' . $expression . '); ?>';
240
            });
241
        }
242
243
        $echoDirectives = [
244
            'actionEditIBlockElement' => 'editIBlockElement',
245
            'actionDeleteIBlockElement' => 'deleteIBlockElement',
246
            'actionEditAndDeleteIBlockElement' => 'editAndDeleteIBlockElement',
247
248
            'actionEditIBlockSection' => 'editIBlockSection',
249
            'actionDeleteIBlockSection' => 'deleteIBlockSection',
250
            'actionEditAndDeleteIBlockSection' => 'editAndDeleteIBlockSection',
251
252
            'actionEditHLBlockElement' => 'editHLBlockElement',
253
            'actionDeleteHLBlockElement' => 'deleteHLBlockElement',
254
            'actionEditAndDeleteHLBlockElement' => 'editAndDeleteHLBlockElement',
255
        ];
256 View Code Duplication
        foreach ($echoDirectives as $directive => $action) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
257
            $compiler->directive($directive, function ($expression) use ($action) {
258
                $expression = rtrim($expression, ')');
259
                $expression = ltrim($expression, '(');
260
                return '<?= \Arrilot\BitrixHermitage\Action::' . $action . '($template, ' . $expression . '); ?>';
261
            });
262
        }
263
    }
264
}
265