JsSandboxServiceProvider::provides()   B
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 36
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 36
rs 8.8571
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 1
eloc 27
nc 1
nop 0
crap 2
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of the pinepain/js-sandbox PHP library.
5
 *
6
 * Copyright (c) 2016-2017 Bogdan Padalko <[email protected]>
7
 *
8
 * Licensed under the MIT license: http://opensource.org/licenses/MIT
9
 *
10
 * For the full copyright and license information, please view the
11
 * LICENSE file that was distributed with this source or visit
12
 * http://opensource.org/licenses/MIT
13
 */
14
15
16
namespace Pinepain\JsSandbox\Laravel;
17
18
19
use Illuminate\Contracts\Container\Container;
20
use Illuminate\Support\ServiceProvider;
21
use InvalidArgumentException;
22
use Pinepain\JsSandbox\Common\NativeGlobalObjectWrapper;
23
use Pinepain\JsSandbox\Common\NativeGlobalObjectWrapperInterface;
24
use Pinepain\JsSandbox\Decorators\DecoratorsCollection;
25
use Pinepain\JsSandbox\Decorators\DecoratorsCollectionInterface;
26
use Pinepain\JsSandbox\Decorators\DecoratorSpecBuilder;
27
use Pinepain\JsSandbox\Decorators\DecoratorSpecBuilderInterface;
28
use Pinepain\JsSandbox\Decorators\Definitions\ExecutionContextInjectorDecorator;
29
use Pinepain\JsSandbox\Extractors\Extractor;
30
use Pinepain\JsSandbox\Extractors\ExtractorDefinitionBuilder;
31
use Pinepain\JsSandbox\Extractors\ExtractorDefinitionBuilderInterface;
32
use Pinepain\JsSandbox\Extractors\ExtractorInterface;
33
use Pinepain\JsSandbox\Extractors\ExtractorsCollection;
34
use Pinepain\JsSandbox\Extractors\ExtractorsCollectionInterface;
35
use Pinepain\JsSandbox\Extractors\ObjectComponents\ExtractorsObjectStore;
36
use Pinepain\JsSandbox\Extractors\ObjectComponents\ExtractorsObjectStoreInterface;
37
use Pinepain\JsSandbox\Extractors\PlainExtractors\AnyExtractor;
38
use Pinepain\JsSandbox\Extractors\PlainExtractors\ArrayExtractor;
39
use Pinepain\JsSandbox\Extractors\PlainExtractors\AssocExtractor;
40
use Pinepain\JsSandbox\Extractors\PlainExtractors\BoolExtractor;
41
use Pinepain\JsSandbox\Extractors\PlainExtractors\DateExtractor;
42
use Pinepain\JsSandbox\Extractors\PlainExtractors\DateTimeExtractor;
43
use Pinepain\JsSandbox\Extractors\PlainExtractors\FunctionExtractor;
44
use Pinepain\JsSandbox\Extractors\PlainExtractors\JsonableExtractor;
45
use Pinepain\JsSandbox\Extractors\PlainExtractors\JsonExtractor;
46
use Pinepain\JsSandbox\Extractors\PlainExtractors\NativeObjectExtractor;
47
use Pinepain\JsSandbox\Extractors\PlainExtractors\NullExtractor;
48
use Pinepain\JsSandbox\Extractors\PlainExtractors\NumberExtractor;
49
use Pinepain\JsSandbox\Extractors\PlainExtractors\ObjectExtractor;
50
use Pinepain\JsSandbox\Extractors\PlainExtractors\PrimitiveExtractor;
51
use Pinepain\JsSandbox\Extractors\PlainExtractors\RawExtractor;
52
use Pinepain\JsSandbox\Extractors\PlainExtractors\RegExpExtractor;
53
use Pinepain\JsSandbox\Extractors\PlainExtractors\ScalarExtractor;
54
use Pinepain\JsSandbox\Extractors\PlainExtractors\StringExtractor;
55
use Pinepain\JsSandbox\Extractors\PlainExtractors\UndefinedExtractor;
56
use Pinepain\JsSandbox\Specs\Builder\ArgumentValueBuilder;
57
use Pinepain\JsSandbox\Specs\Builder\ArgumentValueBuilderInterface;
58
use Pinepain\JsSandbox\Specs\Builder\BindingSpecBuilder;
59
use Pinepain\JsSandbox\Specs\Builder\BindingSpecBuilderInterface;
60
use Pinepain\JsSandbox\Specs\Builder\FunctionSpecBuilder;
61
use Pinepain\JsSandbox\Specs\Builder\FunctionSpecBuilderInterface;
62
use Pinepain\JsSandbox\Specs\Builder\ObjectSpecBuilder;
63
use Pinepain\JsSandbox\Specs\Builder\ObjectSpecBuilderInterface;
64
use Pinepain\JsSandbox\Specs\Builder\ParameterSpecBuilder;
65
use Pinepain\JsSandbox\Specs\Builder\ParameterSpecBuilderInterface;
66
use Pinepain\JsSandbox\Specs\Builder\PropertySpecBuilder;
67
use Pinepain\JsSandbox\Specs\Builder\PropertySpecBuilderInterface;
68
use Pinepain\JsSandbox\Specs\ObjectSpecsCollection;
69
use Pinepain\JsSandbox\Specs\ObjectSpecsCollectionInterface;
70
use Pinepain\JsSandbox\Wrappers\ArrayWrapper;
71
use Pinepain\JsSandbox\Wrappers\CallbackGuards\CallbackGuard;
72
use Pinepain\JsSandbox\Wrappers\CallbackGuards\CallbackGuardInterface;
73
use Pinepain\JsSandbox\Wrappers\CallbackGuards\DebugCallbackGuard;
74
use Pinepain\JsSandbox\Wrappers\CallbackGuards\DevCallbackGuard;
75
use Pinepain\JsSandbox\Wrappers\FunctionComponents\ArgumentsExtractor;
76
use Pinepain\JsSandbox\Wrappers\FunctionComponents\ArgumentsExtractorInterface;
77
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionCallHandler;
78
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionCallHandlerInterface;
79
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionDecorator;
80
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionDecoratorInterface;
81
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionExceptionHandler;
82
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionExceptionHandlerInterface;
83
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionWrappersCache;
84
use Pinepain\JsSandbox\Wrappers\FunctionComponents\FunctionWrappersCacheInterface;
85
use Pinepain\JsSandbox\Wrappers\FunctionComponents\ReturnValueSetter;
86
use Pinepain\JsSandbox\Wrappers\FunctionComponents\ReturnValueSetterInterface;
87
use Pinepain\JsSandbox\Wrappers\FunctionWrapper;
88
use Pinepain\JsSandbox\Wrappers\ObjectComponents\PropertiesHandler;
89
use Pinepain\JsSandbox\Wrappers\ObjectComponents\PropertiesHandlerInterface;
90
use Pinepain\JsSandbox\Wrappers\ObjectComponents\WrappersObjectStore;
91
use Pinepain\JsSandbox\Wrappers\ObjectComponents\WrappersObjectStoreInterface;
92
use Pinepain\JsSandbox\Wrappers\ObjectWrapper;
93
use Pinepain\JsSandbox\Wrappers\PrimitiveWrapper;
94
use Pinepain\JsSandbox\Wrappers\Wrapper;
95
use Pinepain\JsSandbox\Wrappers\WrapperInterface;
96
use Pinepain\ObjectMaps\ObjectBiMap;
97
use Pinepain\ObjectMaps\ObjectMap;
98
use V8\Context;
99
use V8\Isolate;
100
101
102
class JsSandboxServiceProvider extends ServiceProvider
103
{
104
    protected $defer = true;
105
106
    public function register()
107
    {
108
        $this->registerIsolateAndContext();
109
        $this->registerCallbackGuard();
110
        $this->registerFunctionCallHandler();
111
        $this->registerWrapper();
112
        $this->registerExtractor();
113
        $this->registerCommon();
114
    }
115
116
    protected function registerIsolateAndContext()
117
    {
118
        $this->app->singleton(Isolate::class, function (/*Container $app*/) {
119
            return new Isolate();
120
        });
121
122
        $this->app->singleton(Context::class, function (Container $app) {
123
            return new Context($app->make(Isolate::class));
124
        });
125
    }
126
127
    protected function registerCallbackGuard()
128
    {
129
130
        $config = $this->app->make('config');
131
132
        $guards = [
133
            'prod'  => CallbackGuard::class,
134
            'dev'   => DevCallbackGuard::class,
135
            'debug' => DebugCallbackGuard::class,
136
        ];
137
138
        $guard = $config->get('js_sandbox.guard', 'auto');
139
140
        if ('auto' == $guard) {
141
            if ($config->get('app.debug')) {
142
                if ($this->app->environment('production')) {
143
                    $guard = 'debug';
144
                } else {
145
                    $guard = 'dev';
146
                }
147
            } else {
148
                if ($this->app->environment('production')) {
149
                    $guard = 'prod';
150
                } else {
151
                    $guard = 'debug';
152
                }
153
            }
154
        }
155
156
        if (!isset($guards[$guard])) {
157
            $expected = '[\'auto\', \'' . implode('\', \'', array_keys($guards)) . '\']';
158
            throw new InvalidArgumentException("Invalid guard mode specified: expected one of {$expected}, '$guard' given instead");
159
        }
160
161
162
        $this->app->singleton(CallbackGuardInterface::class, $guards[$guard]);
163
164
    }
165
166
    protected function registerFunctionCallHandler()
167
    {
168
        $this->app->singleton(ArgumentsExtractorInterface::class, ArgumentsExtractor::class);
169
        $this->app->singleton(FunctionDecoratorInterface::class, FunctionDecorator::class);
170
        $this->app->singleton(FunctionExceptionHandlerInterface::class, FunctionExceptionHandler::class);
171
        $this->app->singleton(ReturnValueSetterInterface::class, ReturnValueSetter::class);
172
173
        $this->app->singleton(FunctionCallHandlerInterface::class, FunctionCallHandler::class);
174
175
176
        $this->app->singleton(DecoratorsCollectionInterface::class, function (Container $app) {
0 ignored issues
show
Unused Code introduced by
The parameter $app is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
177
178
            $collection = new DecoratorsCollection();
179
180
            $collection->put('inject-context', new ExecutionContextInjectorDecorator());
181
182
            return $collection;
183
        });
184
    }
185
186
    protected function registerWrapper()
187
    {
188
        $function_wrappers_map = new ObjectMap(ObjectMap::WEAK_VALUE);
189
190
        $this->app->singleton(ObjectSpecsCollectionInterface::class, ObjectSpecsCollection::class);
191
        $this->app->singleton(FunctionWrappersCacheInterface::class, function () use ($function_wrappers_map) {
192
            return new FunctionWrappersCache($function_wrappers_map);
193
        });
194
195
        $object_store_map = new ObjectBiMap();
196
197
        // $this->app->when(WrappersObjectStore::class)
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
198
        //           ->needs(ObjectMapInterface::class)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
199
        //           ->give(function () use ($object_store_map) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
200
        //               return $object_store_map;
201
        //           });
202
        //
203
        // $this->app->when(ExtractorsObjectStoreInterface::class)
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
204
        //           ->needs(ObjectMapInterface::class)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
205
        //           ->give(function () use ($object_store_map) {
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
206
        //               return $object_store_map->values();
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
207
        //           });
208
        //
209
        // $this->app->singleton(WrappersObjectStoreInterface::class, WrappersObjectStore::class);
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
210
        // $this->app->singleton(ExtractorsObjectStoreInterface::class, ExtractorsObjectStore::class);
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
211
212
        $this->app->instance(WrappersObjectStoreInterface::class, new WrappersObjectStore($object_store_map));
213
        $this->app->instance(ExtractorsObjectStoreInterface::class, new ExtractorsObjectStore($object_store_map->values()));
214
215
        $this->app->singleton(PropertiesHandlerInterface::class, PropertiesHandler::class);
216
217
        $this->app->singleton(WrapperInterface::class, function (Container $app) {
218
219
            $wrapper = new Wrapper();
220
221
            $primitive_wrapper = $app->make(PrimitiveWrapper::class);
222
223
            $array_wrapper = $app->make(ArrayWrapper::class);
224
            $array_wrapper->setWrapper($wrapper);
225
226
            $function_wrapper = $app->make(FunctionWrapper::class);
227
            $function_wrapper->setWrapper($wrapper);
228
229
            $object_wrapper = $app->make(ObjectWrapper::class);
230
            $object_wrapper->setWrapper($wrapper);
231
232
            $wrapper->setPrimitiveWrapper($primitive_wrapper);
233
            $wrapper->setArrayWrapper($array_wrapper);
234
            $wrapper->setFunctionWrapper($function_wrapper);
235
            $wrapper->setObjectWrapper($object_wrapper);
236
237
            return $wrapper;
238
        });
239
    }
240
241
    protected function registerExtractor()
242
    {
243
        $this->app->singleton(ExtractorDefinitionBuilderInterface::class, ExtractorDefinitionBuilder::class);
244
        $this->app->singleton(PropertySpecBuilderInterface::class, PropertySpecBuilder::class);
245
        $this->app->singleton(ArgumentValueBuilderInterface::class, ArgumentValueBuilder::class);
246
        $this->app->singleton(ParameterSpecBuilderInterface::class, ParameterSpecBuilder::class);
247
        $this->app->singleton(DecoratorSpecBuilderInterface::class, DecoratorSpecBuilder::class);
248
        $this->app->singleton(FunctionSpecBuilderInterface::class, FunctionSpecBuilder::class);
249
        $this->app->singleton(BindingSpecBuilderInterface::class, BindingSpecBuilder::class);
250
        $this->app->singleton(ObjectSpecBuilderInterface::class, ObjectSpecBuilder::class);
251
252
        $this->app->singleton(ExtractorInterface::class, Extractor::class);
253
254
        $this->app->singleton(ExtractorsCollectionInterface::class, function (Container $app) {
255
256
            $collection = new ExtractorsCollection();
257
258
            // TODO: register basic extractor
259
260
            $collection->put('[]', $assoc = new AssocExtractor());
261
            $collection->put('array', $array = new ArrayExtractor(new AssocExtractor(false)));
262
263
            $collection->put('raw', $raw = new RawExtractor());
264
            $collection->put('primitive', $primitive = new PrimitiveExtractor());
265
266
            $collection->put('string', $string = new StringExtractor());
267
            $collection->put('number', $number = new NumberExtractor());
268
            $collection->put('bool', $bool = new BoolExtractor());
269
            $collection->put('null', $null = new NullExtractor());
270
            $collection->put('undefined', $undefined = new UndefinedExtractor());
271
272
            $collection->put('regexp', $regexp = new RegExpExtractor());
273
            $collection->put('date', $date = new DateExtractor());
274
            $collection->put('datetime', $datetime = new DateTimeExtractor());
275
            $collection->put('object', $object = new ObjectExtractor());
276
            $collection->put('function', $function = new FunctionExtractor());
277
            $collection->put('native-object', $instance = $app->make(NativeObjectExtractor::class));
278
279
            $collection->put('json', $json = new JsonExtractor());
280
            $collection->put('jsonable', $json = new JsonableExtractor());
281
282
            $collection->put('scalar', $scalar = new ScalarExtractor($string, $number, $bool, $null, $undefined));
283
            $collection->put('any', $any = new AnyExtractor($scalar, $regexp, $datetime, $assoc));
284
285
            return $collection;
286
        });
287
    }
288
289
    public function registerCommon()
290
    {
291
        $this->app->singleton(NativeGlobalObjectWrapperInterface::class, function (Container $app) {
292
            return new NativeGlobalObjectWrapper(
293
                $app->make(Isolate::class),
294
                $app->make(Context::class),
295
                $app->make(Context::class)->globalObject(),
296
                $app->make(WrapperInterface::class)
297
            );
298
        });
299
    }
300
301
    public function provides()
302
    {
303
        return [
304
            Isolate::class,
305
            Context::class,
306
307
            CallbackGuardInterface::class,
308
309
            ArgumentsExtractorInterface::class,
310
            FunctionDecoratorInterface::class,
311
            FunctionExceptionHandlerInterface::class,
312
            ReturnValueSetterInterface::class,
313
            FunctionCallHandlerInterface::class,
314
315
            ObjectSpecsCollectionInterface::class,
316
            FunctionWrappersCacheInterface::class,
317
            WrappersObjectStoreInterface::class,
318
            PropertiesHandlerInterface::class,
319
            WrapperInterface::class,
320
321
            ExtractorDefinitionBuilderInterface::class,
322
            PropertySpecBuilderInterface::class,
323
            ArgumentValueBuilderInterface::class,
324
            ParameterSpecBuilderInterface::class,
325
            DecoratorSpecBuilderInterface::class,
326
            FunctionSpecBuilderInterface::class,
327
            BindingSpecBuilderInterface::class,
328
            ObjectSpecBuilderInterface::class,
329
330
            ExtractorsCollectionInterface::class,
331
            ExtractorsObjectStoreInterface::class,
332
            ExtractorInterface::class,
333
334
            NativeGlobalObjectWrapperInterface::class,
335
        ];
336
    }
337
}
338