Completed
Push — 1.3-themes-killme ( e5a504 )
by Kamil
13:48
created

getBundleNameFromResourcePath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
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\KernelInterface;
19
20
final class BundleResourceLocator implements ResourceLocatorInterface
21
{
22
    /** @var Filesystem */
23
    private $filesystem;
24
25
    /** @var KernelInterface */
26
    private $kernel;
27
28
    public function __construct(Filesystem $filesystem, KernelInterface $kernel)
29
    {
30
        $this->filesystem = $filesystem;
31
        $this->kernel = $kernel;
32
    }
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function locateResource(string $resourcePath, ThemeInterface $theme): string
38
    {
39
        $this->assertResourcePathIsValid($resourcePath);
40
41
        if (false !== strpos($resourcePath, 'Bundle/Resources/views/')) {
42
            // When using bundle notation, we get a path like @AcmeBundle/Resources/views/template.html.twig
43
            return $this->locateResourceBasedOnBundleNotation($resourcePath, $theme);
44
        }
45
46
        // When using namespaced Twig paths, we get a path like @Acme/template.html.twig
47
        return $this->locateResourceBasedOnTwigNamespace($resourcePath, $theme);
48
    }
49
50
    private function assertResourcePathIsValid(string $resourcePath): void
51
    {
52
        if (0 !== strpos($resourcePath, '@')) {
53
            throw new \InvalidArgumentException(sprintf('Bundle resource path (given "%s") should start with an "@".', $resourcePath));
54
        }
55
56
        if (false !== strpos($resourcePath, '..')) {
57
            throw new \InvalidArgumentException(sprintf('File name "%s" contains invalid characters (..).', $resourcePath));
58
        }
59
    }
60
61
    private function locateResourceBasedOnBundleNotation(string $resourcePath, ThemeInterface $theme): string
62
    {
63
        $bundleName = substr($resourcePath, 1, strpos($resourcePath, '/') - 1);
64
        $resourceName = substr($resourcePath, strpos($resourcePath, 'Resources/') + strlen('Resources/'));
65
66
        // Symfony 4.0+ always returns a single bundle
67
        $bundles = $this->kernel->getBundle($bundleName, false);
68
69
        // So we need to hack it to support both Symfony 3.4 and Symfony 4.0+
70
        if (!is_array($bundles)) {
71
            $bundles = [$bundles];
72
        }
73
74
        foreach ($bundles as $bundle) {
75
            $path = sprintf('%s/%s/%s', $theme->getPath(), $bundle->getName(), $resourceName);
76
77
            if ($this->filesystem->exists($path)) {
78
                return $path;
79
            }
80
        }
81
82
        throw new ResourceNotFoundException($resourcePath, $theme);
83
    }
84
85
    private function locateResourceBasedOnTwigNamespace(string $resourcePath, ThemeInterface $theme): string
86
    {
87
        $twigNamespace = substr($resourcePath, 1, strpos($resourcePath, '/') - 1);
88
        $bundleName = $twigNamespace . 'Bundle';
89
        $resourceName = substr($resourcePath, strpos($resourcePath, '/') + 1);
90
91
        $path = sprintf('%s/%s/views/%s', $theme->getPath(), $bundleName, $resourceName);
92
93
        if ($this->filesystem->exists($path)) {
94
            return $path;
95
        }
96
97
        throw new ResourceNotFoundException($resourcePath, $theme);
98
    }
99
}
100