Completed
Push — develop ( 0cc20e...dccdc9 )
by Mike
07:04
created

EnvironmentFactory::create()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 0
loc 32
rs 9.408
c 0
b 0
f 0
1
<?php declare(strict_types=1);
2
3
/**
4
 * This file is part of phpDocumentor.
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 *
9
 * @author    Mike van Riel <[email protected]>
10
 * @copyright 2010-2018 Mike van Riel / Naenius (http://www.naenius.com)
11
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
12
 * @link      http://phpdoc.org
13
 */
14
15
namespace phpDocumentor\Transformer\Writer\Twig;
16
17
use phpDocumentor\Descriptor\ProjectDescriptor;
18
use phpDocumentor\Transformer\Transformation;
19
use Twig\Environment;
20
use Twig\Extension\DebugExtension;
21
use Twig\Loader\FilesystemLoader;
22
23
final class EnvironmentFactory
24
{
25
    private $baseEnvironment;
26
27
    public function __construct(Environment $baseEnvironment)
28
    {
29
        $this->baseEnvironment = $baseEnvironment;
30
    }
31
32
    public function create(
33
        ProjectDescriptor $project,
34
        Transformation $transformation,
35
        string $destination
36
    ): Environment {
37
        $callingTemplatePath = $this->getTemplatePath($transformation);
38
39
        $baseTemplatesPath = $transformation->getTransformer()->getTemplates()->getTemplatesPath();
40
41
        $templateFolders = [
42
            $baseTemplatesPath . '/..' . DIRECTORY_SEPARATOR . $callingTemplatePath,
43
            // http://twig.sensiolabs.org/doc/recipes.html#overriding-a-template-that-also-extends-itself
44
            $baseTemplatesPath,
45
        ];
46
47
        // get all invoked template paths, they overrule the calling template path
48
        /** @var \phpDocumentor\Transformer\Template $template */
49
        foreach ($transformation->getTransformer()->getTemplates() as $template) {
50
            $path = $baseTemplatesPath . DIRECTORY_SEPARATOR . $template->getName();
51
            array_unshift($templateFolders, $path);
52
        }
53
54
        // Clone twig because otherwise we cannot re-set the extensions on this twig environment on every run of this
55
        // writer
56
        $env = clone $this->baseEnvironment;
57
        $env->setLoader(new FilesystemLoader($templateFolders));
58
59
        $this->addPhpDocumentorExtension($project, $transformation, $destination, $env);
60
        $this->addExtensionsFromTemplateConfiguration($transformation, $project, $env);
61
62
        return $env;
63
    }
64
65
    /**
66
     * Adds the phpDocumentor base extension to the Twig Environment.
67
     */
68
    private function addPhpDocumentorExtension(
69
        ProjectDescriptor $project,
70
        Transformation $transformation,
71
        string $destination,
72
        Environment $twigEnvironment
73
    ): void {
74
        $base_extension = new Extension($project, $transformation);
75
        $base_extension->setDestination(
76
            substr($destination, strlen($transformation->getTransformer()->getTarget()) + 1)
77
        );
78
        $twigEnvironment->addExtension($base_extension);
79
    }
80
81
    /**
82
     * Tries to add any custom extensions that have been defined in the template or the transformation's configuration.
83
     *
84
     * This method will read the `twig-extension` parameter of the transformation (which inherits the template's
85
     * parameter set) and try to add those extensions to the environment.
86
     *
87
     * @throws \InvalidArgumentException if a twig-extension should be loaded but it could not be found.
88
     */
89
    private function addExtensionsFromTemplateConfiguration(
90
        Transformation $transformation,
91
        ProjectDescriptor $project,
92
        Environment $twigEnvironment
93
    ): void {
94
        $isDebug = $transformation->getParameter('twig-debug')
95
            ? $transformation->getParameter('twig-debug')->getValue()
96
            : false;
97
        if ($isDebug === 'true') {
98
            $twigEnvironment->enableDebug();
99
            $twigEnvironment->enableAutoReload();
100
            $twigEnvironment->addExtension(new DebugExtension());
101
        }
102
103
        /** @var \phpDocumentor\Transformer\Template\Parameter $extension */
104
        foreach ($transformation->getParametersWithKey('twig-extension') as $extension) {
105
            $extensionValue = $extension->getValue();
106
            if (!class_exists($extensionValue)) {
107
                throw new \InvalidArgumentException('Unknown twig extension: ' . $extensionValue);
108
            }
109
110
            // to support 'normal' Twig extensions we check the interface to determine what instantiation to do.
111
            $implementsInterface = in_array(
112
                'phpDocumentor\Transformer\Writer\Twig\ExtensionInterface',
113
                class_implements($extensionValue),
114
                true
115
            );
116
117
            $twigEnvironment->addExtension(
118
                $implementsInterface ? new $extensionValue($project, $transformation) : new $extensionValue()
119
            );
120
        }
121
    }
122
123
    /**
124
     * Returns the path belonging to the template.
125
     */
126
    private function getTemplatePath(Transformation $transformation): string
127
    {
128
        $parts = preg_split('[\\\\|/]', $transformation->getSource());
129
130
        return $parts[0] . DIRECTORY_SEPARATOR . $parts[1];
131
    }
132
}
133