Completed
Push — 1.2-symfony4-part2 ( d403b0...d700e8 )
by Kamil
161:20 queued 144:49
created

BundleResourceLocator::locateResource()   B

Complexity

Conditions 4
Paths 6

Size

Total Lines 25
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 25
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 12
nc 6
nop 2
1
<?php
2
3
/*
4
 * This file is part of the Sylius package.
5
 *
6
 * (c) Paweł Jędrzejewski
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
declare(strict_types=1);
13
14
namespace Sylius\Bundle\ThemeBundle\Locator;
15
16
use Sylius\Bundle\ThemeBundle\Model\ThemeInterface;
17
use Symfony\Component\Filesystem\Filesystem;
18
use Symfony\Component\HttpKernel\Kernel;
19
use Symfony\Component\HttpKernel\KernelInterface;
20
21
final class BundleResourceLocator implements ResourceLocatorInterface
22
{
23
    /**
24
     * @var Filesystem
25
     */
26
    private $filesystem;
27
28
    /**
29
     * @var KernelInterface
30
     */
31
    private $kernel;
32
33
    /**
34
     * @param Filesystem $filesystem
35
     * @param KernelInterface $kernel
36
     */
37
    public function __construct(Filesystem $filesystem, KernelInterface $kernel)
38
    {
39
        $this->filesystem = $filesystem;
40
        $this->kernel = $kernel;
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     *
46
     * @param string $resourcePath Eg. "@AcmeBundle/Resources/views/template.html.twig"
47
     */
48
    public function locateResource(string $resourcePath, ThemeInterface $theme): string
49
    {
50
        $this->assertResourcePathIsValid($resourcePath);
51
52
        $bundleName = $this->getBundleNameFromResourcePath($resourcePath);
53
        $resourceName = $this->getResourceNameFromResourcePath($resourcePath);
54
55
        // Symfony 4.0+ always returns a single bundle
56
        $bundles = $this->kernel->getBundle($bundleName, false);
57
58
        // So we need to hack it to support both Symfony 3.4 and Symfony 4.0+
59
        if (!is_array($bundles)) {
60
            $bundles = [$bundles];
61
        }
62
63
        foreach ($bundles as $bundle) {
64
            $path = sprintf('%s/%s/%s', $theme->getPath(), $bundle->getName(), $resourceName);
65
66
            if ($this->filesystem->exists($path)) {
67
                return $path;
68
            }
69
        }
70
71
        throw new ResourceNotFoundException($resourcePath, $theme);
72
    }
73
74
    /**
75
     * @param string $resourcePath
76
     */
77
    private function assertResourcePathIsValid(string $resourcePath): void
78
    {
79
        if (0 !== strpos($resourcePath, '@')) {
80
            throw new \InvalidArgumentException(sprintf('Bundle resource path (given "%s") should start with an "@".', $resourcePath));
81
        }
82
83
        if (false !== strpos($resourcePath, '..')) {
84
            throw new \InvalidArgumentException(sprintf('File name "%s" contains invalid characters (..).', $resourcePath));
85
        }
86
87
        if (false === strpos($resourcePath, 'Resources/')) {
88
            throw new \InvalidArgumentException(sprintf('Resource path "%s" should be in bundles\' "Resources/" directory.', $resourcePath));
89
        }
90
    }
91
92
    /**
93
     * @param string $resourcePath
94
     *
95
     * @return string
96
     */
97
    private function getBundleNameFromResourcePath(string $resourcePath): string
98
    {
99
        return substr($resourcePath, 1, strpos($resourcePath, '/') - 1);
100
    }
101
102
    /**
103
     * @param string $resourcePath
104
     *
105
     * @return string
106
     */
107
    private function getResourceNameFromResourcePath(string $resourcePath): string
108
    {
109
        return substr($resourcePath, strpos($resourcePath, 'Resources/') + strlen('Resources/'));
110
    }
111
}
112