Completed
Pull Request — master (#3)
by
unknown
02:52
created

AppConfig::setTranslator()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 17
Code Lines 10

Duplication

Lines 17
Ratio 100 %

Importance

Changes 0
Metric Value
dl 17
loc 17
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 10
nc 6
nop 1
1
<?php
2
3
namespace Charcoal\App;
4
5
use Exception;
6
use InvalidArgumentException;
7
8
// From PSR-7
9
use Psr\Http\Message\UriInterface;
10
11
// From Slim
12
use Slim\Http\Uri;
13
14
// From 'charcoal-config'
15
use Charcoal\Config\AbstractConfig;
16
17
// From 'charcoal-view'
18
use Charcoal\View\ViewConfig;
19
20
// From 'charcoal-app'
21
use Charcoal\App\Config\CacheConfig;
22
use Charcoal\App\Config\FilesystemConfig;
23
use Charcoal\App\Config\LoggerConfig;
24
25
/**
26
 * Charcoal App configuration
27
 */
28
class AppConfig extends AbstractConfig
29
{
30
    /**
31
     * The application's timezone.
32
     *
33
     * @var string|null
34
     */
35
    private $timezone;
36
37
    /**
38
     * The application's name.
39
     *
40
     * For internal usage.
41
     *
42
     * @var string|null
43
     */
44
    private $projectName;
45
46
    /**
47
     * The base path for the Charcoal installation.
48
     *
49
     * @var string|null
50
     */
51
    private $basePath;
52
53
    /**
54
     * The base URL (public) for the Charcoal installation.
55
     *
56
     * @var UriInterface|null
57
     */
58
    private $baseUrl;
59
60
    /**
61
     * The path to the public / web directory.
62
     *
63
     * @var string|null
64
     */
65
    private $publicPath;
66
67
    /**
68
     * The path to the storage directory.
69
     *
70
     * @var string|null
71
     */
72
    private $storagePath;
73
74
    /**
75
     * Whether the debug mode is enabled (TRUE) or not (FALSE).
76
     *
77
     * @var boolean
78
     */
79
    private $devMode = false;
80
81
    /**
82
     * The application's routes.
83
     *
84
     * @var array
85
     */
86
    private $routes = [];
87
88
    /**
89
     * The application's dynamic routes.
90
     *
91
     * @var array
92
     */
93
    private $routables = [];
94
95
    /**
96
     * The application's handlers.
97
     *
98
     * @var array
99
     */
100
    private $handlers = [];
101
102
    /**
103
     * The application's modules.
104
     *
105
     * @var array
106
     */
107
    private $modules = [];
108
109
    /**
110
     * The application's caching configset.
111
     *
112
     * @var CacheConfig
113
     */
114
    private $cache;
115
116
    /**
117
     * The application's logging configset.
118
     *
119
     * @var LoggerConfig
120
     */
121
    private $logger;
122
123
    /**
124
     * The application's view/rendering configset.
125
     *
126
     * @var ViewConfig
127
     */
128
    protected $view;
129
130
    /**
131
     * The application's database configsets.
132
     *
133
     * @var array
134
     */
135
    private $databases = [];
136
137
    /**
138
     * The application's default database configset.
139
     *
140
     * @var string
141
     */
142
    private $defaultDatabase;
143
144
    /**
145
     * The application's filesystem configset.
146
     *
147
     * @var FilesystemConfig
148
     */
149
    private $filesystem;
150
151
    /**
152
     * Default app-config values.
153
     *
154
     * @return array
155
     */
156
    public function defaults()
157
    {
158
        /** @var string $baseDir Presume that Charcoal App _is_ the application */
159
        $baseDir = rtrim(realpath(__DIR__.'/../../../'), '/').'/';
160
161
        return [
162
            'project_name'     => '',
163
            'base_path'        => $baseDir,
164
            'public_path'      => null,
165
            'storage_path'     => null,
166
            'timezone'         => 'UTC',
167
            'routes'           => [],
168
            'routables'        => [],
169
            'handlers'         => [],
170
            'modules'          => [],
171
            'cache'            => [],
172
            'logger'           => [],
173
            'view'             => [],
174
            'databases'        => [],
175
            'default_database' => 'default',
176
            'dev_mode'         => false
177
        ];
178
    }
179
180
    /**
181
     * Set the application's absolute root path.
182
     *
183
     * Resolves symlinks with realpath() and ensure trailing slash.
184
     *
185
     * @param  string $path The absolute path to the application's root directory.
186
     * @throws InvalidArgumentException If the argument is not a string.
187
     * @return AppConfig Chainable
188
     */
189
    public function setBasePath($path)
190
    {
191
        if ($path === null) {
192
            throw new InvalidArgumentException(
193
                'The base path is required.'
194
            );
195
        }
196
197
        if (!is_string($path)) {
198
            throw new InvalidArgumentException(
199
                'The base path must be a string'
200
            );
201
        }
202
203
        $this->basePath = rtrim(realpath($path), '\\/').DIRECTORY_SEPARATOR;
204
205
        return $this;
206
    }
207
208
    /**
209
     * Retrieve the application's absolute root path.
210
     *
211
     * @return string The absolute path to the application's root directory.
212
     */
213
    public function basePath()
214
    {
215
        return $this->basePath;
216
    }
217
218
    /**
219
     * Set the application's absolute path to the public web directory.
220
     *
221
     * @param  string $path The path to the application's public directory.
222
     * @throws InvalidArgumentException If the argument is not a string.
223
     * @return AppConfig Chainable
224
     */
225 View Code Duplication
    public function setPublicPath($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
226
    {
227
        if ($path === null) {
228
            $this->publicPath = null;
229
230
            return $this;
231
        }
232
233
        if (!is_string($path)) {
234
            throw new InvalidArgumentException(
235
                'The public path must be a string'
236
            );
237
        }
238
239
        $this->publicPath = rtrim(realpath($path), '\\/').DIRECTORY_SEPARATOR;
240
241
        return $this;
242
    }
243
244
    /**
245
     * Retrieve the application's absolute path to the public web directory.
246
     *
247
     * @return string The absolute path to the application's public directory.
248
     */
249
    public function publicPath()
250
    {
251
        if (!isset($this->publicPath)) {
252
            return $this->basePath().'www'.DIRECTORY_SEPARATOR;
253
        }
254
255
        return $this->publicPath;
256
    }
257
258
    /**
259
     * Set the application's absolute path to the storage directory.
260
     *
261
     * @param  string|null $path The path to the application's storage directory.
262
     * @throws InvalidArgumentException If the argument is not a string.
263
     * @return $this
264
     */
265 View Code Duplication
    public function setStoragePath($path)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
266
    {
267
        if ($path === null) {
268
            $this->storagePath = null;
269
270
            return $this;
271
        }
272
273
        if (!is_string($path)) {
274
            throw new InvalidArgumentException(
275
                'The storage path must be a string'
276
            );
277
        }
278
279
        $this->storagePath = rtrim(realpath($path), '\\/').DIRECTORY_SEPARATOR;
280
281
        return $this;
282
    }
283
284
    /**
285
     * Get the path to the storage directory.
286
     *
287
     * Note that the storage space is outside of the public access.
288
     *
289
     * @return string
290
     */
291
    public function storagePath()
292
    {
293
        if (!isset($this->storagePath)) {
294
            return $this->basePath().'uploads'.DIRECTORY_SEPARATOR;
295
        }
296
297
        return $this->storagePath;
298
    }
299
300
    /**
301
     * Set the application's fully qualified base URL to the public web directory.
302
     *
303
     * @param  UriInterface|string $uri The base URI to the application's web directory.
304
     * @return AppConfig Chainable
305
     */
306
    public function setBaseUrl($uri)
307
    {
308
        $this->baseUrl = Uri::createFromString($uri);
0 ignored issues
show
Bug introduced by
It seems like $uri defined by parameter $uri on line 306 can also be of type object<Psr\Http\Message\UriInterface>; however, Slim\Http\Uri::createFromString() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
309
310
        return $this;
311
    }
312
313
    /**
314
     * Retrieve the application's fully qualified base URL to the public web directory.
315
     *
316
     * @return UriInterface|null The base URI to the application's web directory.
317
     */
318
    public function baseUrl()
319
    {
320
        return $this->baseUrl;
321
    }
322
323
    /**
324
     * Set the application's default timezone.
325
     *
326
     * @param  string $timezone The timezone string.
327
     * @throws InvalidArgumentException If the argument is not a string.
328
     * @return AppConfig Chainable
329
     */
330
    public function setTimezone($timezone)
331
    {
332
        if (!is_string($timezone)) {
333
            throw new InvalidArgumentException(
334
                'Timezone must be a string.'
335
            );
336
        }
337
        $this->timezone = $timezone;
338
        return $this;
339
    }
340
341
    /**
342
     * Retrieve the application's default timezone.
343
     *
344
     * Will be used by the PHP date and date-time functions.
345
     *
346
     * @return string
347
     */
348
    public function timezone()
349
    {
350
        if (isset($this->timezone)) {
351
            return $this->timezone;
352
        } else {
353
            return 'UTC';
354
        }
355
    }
356
357
    /**
358
     * Sets the project name.
359
     *
360
     * @param string|null $projectName The project name.
361
     * @throws InvalidArgumentException If the project argument is not a string (or null).
362
     * @return AppConfig Chainable
363
     */
364
    public function setProjectName($projectName)
365
    {
366
        if ($projectName === null) {
367
            $this->projectName = null;
368
            return $this;
369
        }
370
        if (!is_string($projectName)) {
371
            throw new InvalidArgumentException(
372
                'Project name must be a string'
373
            );
374
        }
375
        $this->projectName = $projectName;
376
        return $this;
377
    }
378
379
    /**
380
     * @return string|null
381
     */
382
    public function projectName()
383
    {
384
        if ($this->projectName === null) {
385
            $baseUrl = $this->baseUrl();
386
            if ($baseUrl) {
387
                return $baseUrl->getHost();
388
            }
389
        }
390
        return $this->projectName;
391
    }
392
393
    /**
394
     * @param boolean $devMode The "dev mode" flag.
395
     * @return AppConfig Chainable
396
     */
397
    public function setDevMode($devMode)
398
    {
399
        $this->devMode = !!$devMode;
400
        return $this;
401
    }
402
403
    /**
404
     * @return boolean
405
     */
406
    public function devMode()
407
    {
408
        return !!$this->devMode;
409
    }
410
411
    /**
412
     * @param array $view The view configuration structure to set.
413
     * @return AppConfig Chainable
414
     */
415
    public function setView(array $view)
416
    {
417
        if (!isset($this->view)) {
418
            $this->view = [];
0 ignored issues
show
Documentation Bug introduced by
It seems like array() of type array is incompatible with the declared type object<Charcoal\View\ViewConfig> of property $view.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
419
        }
420
421
        $this->view = array_merge($this->view, $view);
0 ignored issues
show
Documentation Bug introduced by
It seems like array_merge($this->view, $view) of type array is incompatible with the declared type object<Charcoal\View\ViewConfig> of property $view.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
422
423
        return $this;
424
    }
425
426
    /**
427
     * Parse the application's route configuration.
428
     *
429
     * @see    \Charcoal\Admin\Config::setRoutes() For a similar implementation.
430
     * @param  array $routes The route configuration structure to set.
431
     * @return AppConfig Chainable
432
     */
433
    public function setRoutes(array $routes)
434
    {
435
        if (!isset($this->routes)) {
436
            $this->routes = [];
437
        }
438
439
        $toIterate = [ 'templates', 'actions', 'scripts' ];
440
        foreach ($routes as $key => $val) {
441
            if (in_array($key, $toIterate) && isset($this->routes[$key])) {
442
                $this->routes[$key] = array_merge($this->routes[$key], $val);
443
            } else {
444
                $this->routes[$key] = $val;
445
            }
446
        }
447
448
        return $this;
449
    }
450
451
    /**
452
     * @return array
453
     */
454
    public function routes()
455
    {
456
        return $this->routes;
457
    }
458
459
    /**
460
     * @param array $routables The routable configuration structure to set.
461
     * @return AppConfig Chainable
462
     */
463
    public function setRoutables(array $routables)
464
    {
465
        $this->routables = $routables;
466
        return $this;
467
    }
468
469
    /**
470
     * @return array
471
     */
472
    public function routables()
473
    {
474
        return $this->routables;
475
    }
476
477
    /**
478
     * Define custom response and error handlers.
479
     *
480
     * Slim provides five standard handlers:
481
     * - "foundHandler"
482
     * - "notFoundHandler"
483
     * - "notAllowedHandler"
484
     * - "errorHandler"
485
     * - "phpErrorHandler"
486
     *
487
     * @param array $handlers The handlers configuration structure to set.
488
     * @return AppConfig Chainable
489
     */
490
    public function setHandlers(array $handlers)
491
    {
492
        $this->handlers = $handlers;
493
        return $this;
494
    }
495
496
    /**
497
     * @return array
498
     */
499
    public function handlers()
500
    {
501
        return $this->handlers;
502
    }
503
504
    /**
505
     * Set the configuration modules.
506
     *
507
     * The modules are defined in a `key`=>`\Charcoal\App\Module\ModuleConfig` structure.
508
     *
509
     * @param array $modules The module configuration structure to set.
510
     * @return AppConfig Chainable
511
     */
512
    public function setModules(array $modules)
513
    {
514
        $this->modules = $modules;
515
        return $this;
516
    }
517
518
    /**
519
     * @return array
520
     */
521
    public function modules()
522
    {
523
        return $this->modules;
524
    }
525
526
    /**
527
     * @param array|CacheConfig $cache The application global cache config.
528
     * @throws InvalidArgumentException If the argument is not an array or a config.
529
     * @return AppConfig Chainable
530
     */
531 View Code Duplication
    public function setCache($cache)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
532
    {
533
        if ($cache instanceof CacheConfig) {
534
            $this->cache = $cache;
535
            $this->cache->addDelegate($this);
536
        } elseif (is_array($cache)) {
537
            $this->cache = new CacheConfig($cache, [$this]);
538
        } else {
539
            throw new InvalidArgumentException(
540
                'Cache must be an array of config options or a CacheConfig object.'
541
            );
542
        }
543
        return $this;
544
    }
545
546
    /**
547
     * Get the application's global `CacheConfig`.
548
     *
549
     * @return CacheConfig
550
     */
551
    public function cache()
552
    {
553
        return $this->cache;
554
    }
555
556
    /**
557
     * @param array|LoggerConfig $logger The global logger config.
558
     * @throws InvalidArgumentException If the argument is not an array or a config.
559
     * @return AppConfig Chainable
560
     */
561 View Code Duplication
    public function setLogger($logger)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
562
    {
563
        if ($logger instanceof LoggerConfig) {
564
            $this->logger = $logger;
565
            $this->logger->addDelegate($this);
566
        } elseif (is_array($logger)) {
567
            $this->logger = new LoggerConfig($logger, [$this]);
568
        } else {
569
            throw new InvalidArgumentException(
570
                'Logger must be an array of config options or a LoggerConfig object.'
571
            );
572
        }
573
        return $this;
574
    }
575
576
    /**
577
     * Get the application's global `LoggerConfig`
578
     *
579
     * @return LoggerConfig
580
     */
581
    public function logger()
582
    {
583
        return $this->logger;
584
    }
585
586
    /**
587
     * @param array $databases The avaiable databases config.
588
     * @return Config Chainable
589
     */
590
    public function setDatabases(array $databases)
591
    {
592
        $this->databases = $databases;
593
        return $this;
594
    }
595
596
    /**
597
     * @throws Exception If trying to access this method and no databases were set.
598
     * @return array
599
     */
600
    public function databases()
601
    {
602
        if ($this->databases === null) {
603
            throw new Exception(
604
                'Invalid app config: Databases are not set.'
605
            );
606
        }
607
        return $this->databases;
608
    }
609
610
    /**
611
     * @param string $ident The ident of the database to return the configuration of.
612
     * @throws InvalidArgumentException If the ident argument is not a string.
613
     * @throws Exception If trying to access an invalid database.
614
     * @return array
615
     */
616
    public function databaseConfig($ident)
617
    {
618
        if (!is_string($ident)) {
619
            throw new InvalidArgumentException(
620
                'Invalid app config: default database must be a string.'
621
            );
622
        }
623
        $databases = $this->databases();
624
        if (!isset($databases[$ident])) {
625
            throw new Exception(
626
                sprintf('Invalid app config: no database configuration matches "%s".', $ident)
627
            );
628
        }
629
        return $databases[$ident];
630
    }
631
632
    /**
633
     * @param string $defaultDatabase The default database ident.
634
     * @throws InvalidArgumentException If the argument is not a string.
635
     * @return AppConfig Chainable
636
     */
637
    public function setDefaultDatabase($defaultDatabase)
638
    {
639
        if (!is_string($defaultDatabase)) {
640
            throw new InvalidArgumentException(
641
                'Invalid app config: Default database must be a string.'
642
            );
643
        }
644
        $this->defaultDatabase = $defaultDatabase;
645
        return $this;
646
    }
647
648
    /**
649
     * @param string $ident  The database ident.
650
     * @param array  $config The database options.
651
     * @throws InvalidArgumentException If the arguments are invalid.
652
     * @return AppConfig Chainable
653
     */
654
    public function addDatabase($ident, array $config)
655
    {
656
        if (!is_string($ident)) {
657
            throw new InvalidArgumentException(
658
                'Invalid app config: database ident must be a string.'
659
            );
660
        }
661
662
        if ($this->databases === null) {
663
            $this->databases = [];
664
        }
665
        $this->databases[$ident] = $config;
666
        return $this;
667
    }
668
669
    /**
670
     * @throws Exception If trying to access this method before a setter.
671
     * @return mixed
672
     */
673
    public function defaultDatabase()
674
    {
675
        if ($this->defaultDatabase === null) {
676
            throw new Exception(
677
                'Invalid app config: default database is not set.'
678
            );
679
        }
680
        return $this->defaultDatabase;
681
    }
682
683
    /**
684
     * @param array|FilesystemConfig $filesystem The application global cache config.
685
     * @throws InvalidArgumentException If the argument is not an array or a config.
686
     * @return AppConfig Chainable
687
     */
688 View Code Duplication
    public function setFilesystem($filesystem)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
689
    {
690
        if ($filesystem instanceof FilesystemConfig) {
691
            $this->filesystem = $filesystem;
692
            $this->filesystem->addDelegate($this);
693
        } elseif (is_array($filesystem)) {
694
            $this->filesystem = new FileSystemConfig($filesystem, [$this]);
695
        } else {
696
            throw new InvalidArgumentException(
697
                'Filesystem must be an array of config options or a FilesystemConfig object.'
698
            );
699
        }
700
        return $this;
701
    }
702
703
    /**
704
     * Get the application's global `FilesystemConfig`
705
     *
706
     * @return FilesystemConfig
707
     */
708
    public function filesystem()
709
    {
710
        return $this->filesystem;
711
    }
712
}
713