Closure::configureModule()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 2
Metric Value
cc 1
eloc 1
c 4
b 0
f 2
nc 1
nop 0
dl 0
loc 4
rs 10
1
<?php
2
/**
3
 * Closure for Craft CMS
4
 *
5
 * Allows you to use arrow function closures in Twig
6
 *
7
 * @link      https://nystudio107.com
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @copyright tag
Loading history...
8
 * @copyright Copyright (c) 2022 nystudio107
0 ignored issues
show
Coding Style introduced by
@copyright tag must contain a year and the name of the copyright holder
Loading history...
9
 */
0 ignored issues
show
Coding Style introduced by
PHP version not specified
Loading history...
Coding Style introduced by
Missing @category tag in file comment
Loading history...
Coding Style introduced by
Missing @package tag in file comment
Loading history...
Coding Style introduced by
Missing @author tag in file comment
Loading history...
Coding Style introduced by
Missing @license tag in file comment
Loading history...
10
11
namespace nystudio107\closure;
12
13
use Craft;
14
use craft\console\Application as CraftConsoleApp;
15
use craft\events\CreateTwigEvent;
16
use craft\web\Application as CraftWebApp;
17
use craft\web\twig\Environment;
18
use craft\web\View;
19
use nystudio107\closure\helpers\Reflection as ReflectionHelper;
20
use nystudio107\closure\twig\ClosureExpressionParser;
21
use ReflectionException;
22
use Twig\Environment as TwigEnvironment;
23
use Twig\Parser;
24
use yii\base\BootstrapInterface;
25
use yii\base\Event;
26
use yii\base\Module;
27
28
/**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
29
 * @author    nystudio107
0 ignored issues
show
Coding Style introduced by
The tag in position 1 should be the @package tag
Loading history...
Coding Style introduced by
Content of the @author tag must be in the form "Display Name <[email protected]>"
Loading history...
Coding Style introduced by
Tag value for @author tag indented incorrectly; expected 2 spaces but found 4
Loading history...
30
 * @package   Closure
0 ignored issues
show
Coding Style introduced by
Tag value for @package tag indented incorrectly; expected 1 spaces but found 3
Loading history...
31
 * @since     1.0.0
0 ignored issues
show
Coding Style introduced by
The tag in position 3 should be the @author tag
Loading history...
Coding Style introduced by
Tag value for @since tag indented incorrectly; expected 3 spaces but found 5
Loading history...
32
 */
0 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
33
class Closure extends Module implements BootstrapInterface
34
{
35
    // Constants
36
    // =========================================================================
37
38
    public const ID = 'closure';
39
40
    // Protected Static Properties
41
    // =========================================================================
42
43
    protected bool $closureAdded = false;
44
45
    // Public Methods
46
    // =========================================================================
47
48
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $id should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $parent should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $config should have a doc-comment as per coding-style.
Loading history...
49
     * @inerhitdoc
50
     */
51
    public function __construct($id = self::ID, $parent = null, $config = [])
52
    {
53
        /**
54
         * Explicitly set the $id parameter, as earlier versions of Yii2 look for a
55
         * default parameter, and depend on $id being explicitly set:
56
         * https://github.com/yiisoft/yii2/blob/f3d1534125c9c3dfe8fa65c28a4be5baa822e721/framework/di/Container.php#L436-L448
57
         */
58
        parent::__construct($id, $parent, $config);
59
    }
60
61
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $app should have a doc-comment as per coding-style.
Loading history...
62
     * @inerhitDoc
63
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
64
    public function bootstrap($app)
65
    {
66
        // Only bootstrap if this is a CraftWebApp
67
        if (!($app instanceof CraftWebApp || $app instanceof CraftConsoleApp)) {
68
            return;
69
        }
70
        // Do nothing if we're running a version of Twig that has baked in support for "arrow functions everywhere"
71
        // @phpstan-ignore-next-line
72
        if (version_compare(TwigEnvironment::VERSION, '3.15.0', '>=')) {
73
            Craft::warning('Craft Closure not loaded because this version of Twig already supports arrow functions everywhere. You can safely uninstall Craft Closure by removing it from your composer.json', __METHOD__);
74
            return;
75
        }
76
        // Set the instance of this module class, so we can later access it with `Closure::getInstance()`
77
        static::setInstance($this);
78
        // Configure our module
79
        $this->configureModule();
80
        // Register our event handlers
81
        $this->registerEventHandlers();
82
        Craft::info('Closure module bootstrapped', __METHOD__);
83
    }
84
85
    // Protected Methods
86
    // =========================================================================
87
88
    /**
89
     * Add our ClosureExpressionParser to default $allowArrow = true to let
90
     * arrow function closures work outside of Twig filter contexts
91
     *
92
     * @param Environment|null $twig
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
93
     * @return void
0 ignored issues
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
94
     */
95
    public function addClosure(?Environment $twig = null): void
96
    {
97
        // Custom environment if specified, otherwise Craft default
98
        $twig = $twig ?? Craft::$app->getView()->getTwig();
99
        // Get the parser object used by Twig
100
        try {
101
            $parserReflection = ReflectionHelper::getReflectionProperty($twig, 'parser');
102
        } catch (ReflectionException $e) {
103
            Craft::error($e->getMessage(), __METHOD__);
104
            return;
105
        }
106
        $parserReflection->setAccessible(true);
107
        $parser = $parserReflection->getValue($twig);
108
        if ($parser === null) {
109
            $parser = new Parser($twig);
110
            $parserReflection->setValue($twig, $parser);
111
        }
112
        // Create the ClosureExpressionParser object and set the parser to use it
113
        try {
114
            $expressionParserReflection = ReflectionHelper::getReflectionProperty($parser, 'expressionParser');
115
        } catch (ReflectionException $e) {
116
            Craft::error($e->getMessage(), __METHOD__);
117
            return;
118
        }
119
        $expressionParserReflection->setAccessible(true);
120
        $expressionParser = new ClosureExpressionParser($parser, $twig);
121
        $expressionParserReflection->setValue($parser, $expressionParser);
122
    }
123
124
    /**
125
     * Configure our module
126
     *
127
     * @return void
128
     */
129
    protected function configureModule(): void
130
    {
131
        // Register our module
132
        Craft::$app->setModule($this->id, $this);
133
    }
134
135
    /**
136
     * Registers our event handlers
137
     *
138
     * @return void
139
     */
140
    protected function registerEventHandlers(): void
141
    {
142
        // Handler: View::EVENT_AFTER_CREATE_TWIG
143
        Event::on(
144
            View::class,
145
            View::EVENT_AFTER_CREATE_TWIG,
146
            fn(CreateTwigEvent $event) => $this->addClosure($event->twig)
147
        );
148
    }
149
}
150