Passed
Push — master ( fcbfb0...64542d )
by
unknown
13:36
created

Extension::createFromExtensionArray()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 9
nc 8
nop 1
dl 0
loc 14
rs 9.6111
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the TYPO3 CMS project.
5
 *
6
 * It is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License, either version 2
8
 * of the License, or any later version.
9
 *
10
 * For the full copyright and license information, please read the
11
 * LICENSE.txt file that was distributed with this source code.
12
 *
13
 * The TYPO3 project - inspiring people to share!
14
 */
15
16
namespace TYPO3\CMS\Extensionmanager\Domain\Model;
17
18
use TYPO3\CMS\Core\Core\Environment;
19
use TYPO3\CMS\Core\Utility\GeneralUtility;
20
use TYPO3\CMS\Core\Utility\MathUtility;
21
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
22
23
/**
24
 * Main extension model
25
 * @internal This class is a specific domain model implementation and is not part of the Public TYPO3 API.
26
 */
27
class Extension extends AbstractEntity
28
{
29
    /**
30
     * Category index for distributions
31
     */
32
    const DISTRIBUTION_CATEGORY = 10;
33
34
    /**
35
     * Contains default categories.
36
     *
37
     * @var array
38
     */
39
    protected static $defaultCategories = [
40
        0 => 'be',
41
        1 => 'module',
42
        2 => 'fe',
43
        3 => 'plugin',
44
        4 => 'misc',
45
        5 => 'services',
46
        6 => 'templates',
47
        8 => 'doc',
48
        9 => 'example',
49
        self::DISTRIBUTION_CATEGORY => 'distribution'
50
    ];
51
52
    /**
53
     * Contains default states.
54
     *
55
     * @var array
56
     */
57
    protected static $defaultStates = [
58
        0 => 'alpha',
59
        1 => 'beta',
60
        2 => 'stable',
61
        3 => 'experimental',
62
        4 => 'test',
63
        5 => 'obsolete',
64
        6 => 'excludeFromUpdates',
65
        7 => 'deprecated',
66
        999 => 'n/a'
67
    ];
68
69
    /**
70
     * @var string
71
     */
72
    protected $extensionKey = '';
73
74
    /**
75
     * @var string
76
     */
77
    protected $version = '';
78
79
    /**
80
     * @var int
81
     */
82
    protected $integerVersion = 0;
83
84
    /**
85
     * @var string
86
     */
87
    protected $title = '';
88
89
    /**
90
     * @var string
91
     */
92
    protected $description = '';
93
94
    /**
95
     * @var int
96
     */
97
    protected $state = 0;
98
99
    /**
100
     * @var int
101
     */
102
    protected $category = 0;
103
104
    /**
105
     * @var \DateTime
106
     */
107
    protected $lastUpdated;
108
109
    /**
110
     * @var string
111
     */
112
    protected $updateComment = '';
113
114
    /**
115
     * @var string
116
     */
117
    protected $authorName = '';
118
119
    /**
120
     * @var string
121
     */
122
    protected $authorEmail = '';
123
124
    /**
125
     * @var bool
126
     */
127
    protected $currentVersion = false;
128
129
    /**
130
     * @var string
131
     */
132
    protected $md5hash = '';
133
134
    /**
135
     * @var int
136
     */
137
    protected $reviewState;
138
139
    /**
140
     * @var int
141
     */
142
    protected $alldownloadcounter;
143
144
    /**
145
     * @var string
146
     */
147
    protected $serializedDependencies = '';
148
149
    /**
150
     * @var \SplObjectStorage<\TYPO3\CMS\Extensionmanager\Domain\Model\Dependency>
151
     */
152
    protected $dependencies;
153
154
    /**
155
     * @var string
156
     */
157
    protected $documentationLink = '';
158
159
    /**
160
     * @var string
161
     */
162
    protected $remote;
163
164
    /**
165
     * @internal
166
     * @var int
167
     */
168
    protected $position = 0;
169
170
    /**
171
     * @param string $authorEmail
172
     */
173
    public function setAuthorEmail($authorEmail)
174
    {
175
        $this->authorEmail = $authorEmail;
176
    }
177
178
    /**
179
     * @return string
180
     */
181
    public function getAuthorEmail()
182
    {
183
        return $this->authorEmail;
184
    }
185
186
    /**
187
     * @param string $authorName
188
     */
189
    public function setAuthorName($authorName)
190
    {
191
        $this->authorName = $authorName;
192
    }
193
194
    /**
195
     * @return string
196
     */
197
    public function getAuthorName()
198
    {
199
        return $this->authorName;
200
    }
201
202
    /**
203
     * @param int $category
204
     */
205
    public function setCategory($category)
206
    {
207
        $this->category = $category;
208
    }
209
210
    /**
211
     * @return int
212
     */
213
    public function getCategory()
214
    {
215
        return $this->category;
216
    }
217
218
    /**
219
     * Get Category String
220
     *
221
     * @return string
222
     */
223
    public function getCategoryString()
224
    {
225
        $categoryString = '';
226
        if (isset(self::$defaultCategories[$this->getCategory()])) {
227
            $categoryString = self::$defaultCategories[$this->getCategory()];
228
        }
229
        return $categoryString;
230
    }
231
232
    /**
233
     * Returns category index from a given string or an integer.
234
     * Fallback to 4 - 'misc' in case string is not found or integer ist out of range.
235
     *
236
     * @param string|int $category Category string or integer
237
     * @return int Valid category index
238
     */
239
    public function getCategoryIndexFromStringOrNumber($category)
240
    {
241
        $categoryIndex = 4;
242
        if (MathUtility::canBeInterpretedAsInteger($category)) {
243
            $categoryIndex = (int)$category;
244
            if ($categoryIndex < 0 || $categoryIndex > 10) {
245
                $categoryIndex = 4;
246
            }
247
        } elseif (is_string($category)) {
248
            $categoryIndex = array_search($category, self::$defaultCategories);
249
            if ($categoryIndex === false) {
250
                $categoryIndex = 4;
251
            }
252
        }
253
        return $categoryIndex;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $categoryIndex also could return the type string which is incompatible with the documented return type integer.
Loading history...
254
    }
255
256
    /**
257
     * @param string $description
258
     */
259
    public function setDescription($description)
260
    {
261
        $this->description = $description;
262
    }
263
264
    /**
265
     * @return string
266
     */
267
    public function getDescription()
268
    {
269
        return $this->description;
270
    }
271
272
    /**
273
     * @param string $extensionKey
274
     */
275
    public function setExtensionKey($extensionKey)
276
    {
277
        $this->extensionKey = $extensionKey;
278
    }
279
280
    /**
281
     * @return string
282
     */
283
    public function getExtensionKey()
284
    {
285
        return $this->extensionKey;
286
    }
287
288
    /**
289
     * @param \DateTime $lastUpdated
290
     */
291
    public function setLastUpdated(\DateTime $lastUpdated)
292
    {
293
        $this->lastUpdated = $lastUpdated;
294
    }
295
296
    /**
297
     * @return \DateTime
298
     */
299
    public function getLastUpdated()
300
    {
301
        return $this->lastUpdated;
302
    }
303
304
    /**
305
     * @param int $state
306
     */
307
    public function setState($state)
308
    {
309
        $this->state = $state;
310
    }
311
312
    /**
313
     * @return int
314
     */
315
    public function getState()
316
    {
317
        return $this->state;
318
    }
319
320
    /**
321
     * Get State string
322
     *
323
     * @return string
324
     */
325
    public function getStateString()
326
    {
327
        $stateString = '';
328
        if (isset(self::$defaultStates[$this->getState()])) {
329
            $stateString = self::$defaultStates[$this->getState()];
330
        }
331
        return $stateString;
332
    }
333
334
    /**
335
     * Returns either array with all default states or index/title
336
     * of a state entry.
337
     *
338
     * @param mixed $state state title or state index
339
     * @return mixed
340
     */
341
    public function getDefaultState($state = null)
342
    {
343
        $defaultState = '';
344
        if ($state === null) {
345
            $defaultState = self::$defaultStates;
346
        } else {
347
            if (is_string($state)) {
348
                $stateIndex = array_search(strtolower($state), self::$defaultStates);
349
                if ($stateIndex === false) {
350
                    // default state
351
                    $stateIndex = 999;
352
                }
353
                $defaultState = $stateIndex;
354
            } else {
355
                if (is_int($state) && $state >= 0) {
356
                    if (array_key_exists($state, self::$defaultStates)) {
357
                        $stateTitle = self::$defaultStates[$state];
358
                    } else {
359
                        // default state
360
                        $stateTitle = 'n/a';
361
                    }
362
                    $defaultState = $stateTitle;
363
                }
364
            }
365
        }
366
        return $defaultState;
367
    }
368
369
    /**
370
     * @param string $title
371
     */
372
    public function setTitle($title)
373
    {
374
        $this->title = $title;
375
    }
376
377
    /**
378
     * @return string
379
     */
380
    public function getTitle()
381
    {
382
        return $this->title;
383
    }
384
385
    /**
386
     * @param string $updateComment
387
     */
388
    public function setUpdateComment($updateComment)
389
    {
390
        $this->updateComment = $updateComment;
391
    }
392
393
    /**
394
     * @return string
395
     */
396
    public function getUpdateComment()
397
    {
398
        return $this->updateComment;
399
    }
400
401
    /**
402
     * @param string $version
403
     */
404
    public function setVersion($version)
405
    {
406
        $this->version = $version;
407
    }
408
409
    /**
410
     * @return string
411
     */
412
    public function getVersion()
413
    {
414
        return $this->version;
415
    }
416
417
    /**
418
     * @param bool $currentVersion
419
     */
420
    public function setCurrentVersion($currentVersion)
421
    {
422
        $this->currentVersion = $currentVersion;
423
    }
424
425
    /**
426
     * @return bool
427
     */
428
    public function getCurrentVersion()
429
    {
430
        return $this->currentVersion;
431
    }
432
433
    /**
434
     * @param string $md5hash
435
     */
436
    public function setMd5hash($md5hash)
437
    {
438
        $this->md5hash = $md5hash;
439
    }
440
441
    /**
442
     * @return string
443
     */
444
    public function getMd5hash()
445
    {
446
        return $this->md5hash;
447
    }
448
449
    /**
450
     * Possible install paths
451
     *
452
     * @static
453
     * @return array
454
     */
455
    public static function returnInstallPaths()
456
    {
457
        $installPaths = [
458
            'System' => Environment::getFrameworkBasePath() . '/',
459
            'Global' => Environment::getBackendPath() . '/ext/',
460
            'Local' => Environment::getExtensionsPath() . '/'
461
        ];
462
        return $installPaths;
463
    }
464
465
    /**
466
     * Allowed install paths
467
     *
468
     * @static
469
     * @return array
470
     */
471
    public static function returnAllowedInstallPaths()
472
    {
473
        $installPaths = self::returnInstallPaths();
474
        if (empty($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowGlobalInstall'])) {
475
            unset($installPaths['Global']);
476
        }
477
        if (empty($GLOBALS['TYPO3_CONF_VARS']['EXT']['allowLocalInstall'])) {
478
            unset($installPaths['Local']);
479
        }
480
        return $installPaths;
481
    }
482
483
    /**
484
     * Allowed install names: System, Global, Local
485
     *
486
     * @static
487
     * @return array
488
     */
489
    public static function returnAllowedInstallTypes()
490
    {
491
        $installPaths = self::returnAllowedInstallPaths();
492
        return array_keys($installPaths);
493
    }
494
495
    /**
496
     * @param string $dependencies
497
     */
498
    public function setSerializedDependencies($dependencies)
499
    {
500
        $this->serializedDependencies = $dependencies;
501
    }
502
503
    /**
504
     * @return string
505
     */
506
    public function getSerializedDependencies()
507
    {
508
        return $this->serializedDependencies;
509
    }
510
511
    /**
512
     * @param \SplObjectStorage $dependencies
513
     */
514
    public function setDependencies($dependencies)
515
    {
516
        $this->dependencies = $dependencies;
517
    }
518
519
    /**
520
     * @return \SplObjectStorage
521
     */
522
    public function getDependencies()
523
    {
524
        if (!is_object($this->dependencies)) {
525
            $this->setDependencies($this->convertDependenciesToObjects($this->getSerializedDependencies()));
526
        }
527
        return $this->dependencies;
528
    }
529
530
    public function getTypo3Dependency(): ?Dependency
531
    {
532
        foreach ($this->getDependencies() as $dependency) {
533
            if ($dependency->getIdentifier() === 'typo3') {
534
                return $dependency;
535
            }
536
        }
537
        return null;
538
    }
539
540
    /**
541
     * @param Dependency $dependency
542
     */
543
    public function addDependency(Dependency $dependency)
544
    {
545
        $this->dependencies->attach($dependency);
546
    }
547
548
    /**
549
     * @param int $integerVersion
550
     */
551
    public function setIntegerVersion($integerVersion)
552
    {
553
        $this->integerVersion = $integerVersion;
554
    }
555
556
    /**
557
     * @return int
558
     */
559
    public function getIntegerVersion()
560
    {
561
        return $this->integerVersion;
562
    }
563
564
    /**
565
     * @param int $reviewState
566
     */
567
    public function setReviewState($reviewState)
568
    {
569
        $this->reviewState = $reviewState;
570
    }
571
572
    /**
573
     * @return int
574
     */
575
    public function getReviewState()
576
    {
577
        return $this->reviewState;
578
    }
579
580
    /**
581
     * @param int $position
582
     */
583
    public function setPosition($position)
584
    {
585
        $this->position = $position;
586
    }
587
588
    /**
589
     * @return int
590
     */
591
    public function getPosition()
592
    {
593
        return $this->position;
594
    }
595
596
    /**
597
     * @param int $alldownloadcounter
598
     */
599
    public function setAlldownloadcounter($alldownloadcounter)
600
    {
601
        $this->alldownloadcounter = $alldownloadcounter;
602
    }
603
604
    /**
605
     * @return int
606
     */
607
    public function getAlldownloadcounter()
608
    {
609
        return $this->alldownloadcounter;
610
    }
611
612
    /**
613
     * @return string
614
     */
615
    public function getDocumentationLink(): string
616
    {
617
        return $this->documentationLink;
618
    }
619
620
    /**
621
     * @param string $documentationLink
622
     */
623
    public function setDocumentationLink(string $documentationLink): void
624
    {
625
        $this->documentationLink = $documentationLink;
626
    }
627
628
    public function getRemoteIdentifier(): string
629
    {
630
        return $this->remote;
631
    }
632
633
    /**
634
     * Map a legacy extension array to an object
635
     *
636
     * @param array $extensionArray
637
     * @return Extension
638
     */
639
    public static function createFromExtensionArray(array $extensionArray): self
640
    {
641
        $extension = GeneralUtility::makeInstance(self::class);
642
        $extension->setExtensionKey($extensionArray['key']);
643
        if (isset($extensionArray['version'])) {
644
            $extension->setVersion($extensionArray['version']);
645
        }
646
        if (isset($extensionArray['remote'])) {
647
            $extension->remote = $extensionArray['remote'];
648
        }
649
        if (isset($extensionArray['constraints'])) {
650
            $extension->setDependencies($extension->convertDependenciesToObjects(is_array($extensionArray['constraints']) ? serialize($extensionArray['constraints']) : $extensionArray['constraints']));
651
        }
652
        return $extension;
653
    }
654
655
    /**
656
     * Converts string dependencies to an object storage of dependencies
657
     *
658
     * @param string $dependencies
659
     * @return \SplObjectStorage
660
     */
661
    protected function convertDependenciesToObjects(string $dependencies): \SplObjectStorage
662
    {
663
        $dependenciesObject = new \SplObjectStorage();
664
        $unserializedDependencies = unserialize($dependencies, ['allowed_classes' => false]);
665
        if (!is_array($unserializedDependencies)) {
666
            return $dependenciesObject;
667
        }
668
        foreach ($unserializedDependencies as $dependencyType => $dependencyValues) {
669
            // Dependencies might be given as empty string, e.g. conflicts => ''
670
            if (!is_array($dependencyValues)) {
671
                continue;
672
            }
673
            if (!$dependencyType) {
674
                continue;
675
            }
676
            foreach ($dependencyValues as $dependency => $versionConstraint) {
677
                if ($dependency) {
678
                    $dependencyObject = Dependency::createFromEmConf($dependency, $versionConstraint, $dependencyType);
679
                    $dependenciesObject->attach($dependencyObject);
680
                }
681
            }
682
        }
683
        return $dependenciesObject;
684
    }
685
}
686