• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

FluidTYPO3 / flux / 8984651213

07 May 2024 11:37AM UTC coverage: 93.421% (-0.09%) from 93.508%
8984651213

push

github

NamelessCoder
[TER] 10.0.10

6802 of 7281 relevant lines covered (93.42%)

46.26 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.77
/Classes/Content/TypeDefinition/FluidFileBased/DropInContentTypeDefinition.php
1
<?php
2
declare(strict_types=1);
3
namespace FluidTYPO3\Flux\Content\TypeDefinition\FluidFileBased;
4

5
/*
6
 * This file is part of the FluidTYPO3/Flux project under GPLv2 or later.
7
 *
8
 * For the full copyright and license information, please read the
9
 * LICENSE.md file that was distributed with this source code.
10
 */
11

12
use FluidTYPO3\Flux\Enum\ExtensionOption;
13
use FluidTYPO3\Flux\Provider\Provider;
14
use FluidTYPO3\Flux\Utility\ExtensionConfigurationUtility;
15
use Symfony\Component\Finder\Exception\DirectoryNotFoundException;
16
use Symfony\Component\Finder\Finder;
17
use TYPO3\CMS\Core\Core\Environment;
18
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
19
use TYPO3\CMS\Core\Utility\GeneralUtility;
20

21
/**
22
 * Drop-in Fluid Content Type Definition
23
 *
24
 * Holds one set of metadata to operate a single content type
25
 * based on a template file located in the site-wide, drop-in
26
 * resources location.
27
 */
28
class DropInContentTypeDefinition extends FluidFileBasedContentTypeDefinition
29
{
30
    public const DESIGN_DIRECTORY = 'design/';
31
    public const TEMPLATES_DIRECTORY = 'Templates/';
32
    public const PARTIALS_DIRECTORY = 'Partials/';
33
    public const LAYOUTS_DIRECTORY = 'Layouts/';
34
    public const TEMPLATES_PATTERN = '*.html';
35
    public const CONTENT_DIRECTORY = 'Content/';
36
    public const PAGE_DIRECTORY = 'Page/';
37

38
    protected string $extensionIdentity = 'FluidTYPO3.Flux';
39
    protected string $basePath = 'design/';
40
    protected string $relativeFilePath = '';
41
    protected string $providerClassName = Provider::class;
42

43
    /**
44
     * Constructs a Fluid file-based content type definition
45
     *
46
     * Can be used to construct definitions based on template files
47
     * which contain Flux form definitions and supports sub-folders
48
     * for template files by specifying $relativeFilePath as a path
49
     * inside a folder relative to the $basePath.
50
     *
51
     * @param string $extensionIdentity The VendorName.ExtensionName identity of the extension that contains the file
52
     * @param string $basePath Absolute path, or EXT:... path to location of template file
53
     * @param string $relativeFilePath Path of file relative to $basePath, without leading slash
54
     * @param string $providerClassName Class name of a Flux ProviderInterface implementation that handles the CType
55
     */
56
    public function __construct(
57
        string $extensionIdentity,
58
        string $basePath,
59
        string $relativeFilePath,
60
        string $providerClassName = Provider::class
61
    ) {
62
        $this->extensionIdentity = $extensionIdentity;
10✔
63
        $this->basePath = static::determineAbsolutePathForFilename($basePath);
10✔
64
        $this->relativeFilePath = $relativeFilePath;
10✔
65
        $this->providerClassName = $providerClassName;
10✔
66
    }
67

68
    /**
69
     * @return iterable|DropInContentTypeDefinition[]
70
     */
71
    public static function fetchContentTypes(): iterable
72
    {
73
        if (!ExtensionConfigurationUtility::getOption(ExtensionOption::OPTION_PLUG_AND_PLAY)) {
20✔
74
            // Do not return or auto-create any plug and play templates if the extension config option is disabled.
75
            // Option default value is ENABLED (hence null coalesce to TRUE if not defined)
76
            return [];
5✔
77
        }
78
        // Steps:
79
        // 1) auto-create if missing, the required file structure and dummy files
80
        // 2) iterate all content types found in the file structure
81
        $plugAndPlayDirectory = ExtensionConfigurationUtility::getOption(
15✔
82
            ExtensionOption::OPTION_PLUG_AND_PLAY_DIRECTORY
15✔
83
        );
15✔
84
        if (!is_scalar($plugAndPlayDirectory)) {
15✔
85
            return [];
5✔
86
        }
87
        $basePath = trim((string) $plugAndPlayDirectory, '/.');
10✔
88
        if (empty($basePath)) {
10✔
89
            return [];
×
90
        }
91
        $basePath = static::determineAbsolutePathForFilename($basePath) . '/';
10✔
92
        static::initializeDropInFileSystemStructure($basePath);
10✔
93

94
        $contentTypesPath = $basePath . static::TEMPLATES_DIRECTORY . static::CONTENT_DIRECTORY;
10✔
95
        /** @var Finder $finder */
96
        $finder = GeneralUtility::makeInstance(Finder::class);
10✔
97
        try {
98
            /** @var \SplFileInfo[] $files */
99
            $files = $finder->in($contentTypesPath)->name(static::TEMPLATES_PATTERN)->sortByName();
10✔
100
        } catch (DirectoryNotFoundException $exception) {
5✔
101
            return [];
5✔
102
        }
103
        $types = [];
5✔
104
        $basePathLength = strlen($contentTypesPath);
5✔
105
        foreach ($files as $file) {
5✔
106
            $templateFile = $file->getPath() . '/' . $file->getFilename();
5✔
107
            // May cause some files to be ignored if the files are either symlinked or the base path was not possible
108
            // to resolve correctly. This can happen if for some reason, ENV is configured with a public path that is
109
            // not within the project path, is is configured as an absolute path (which technically isn't correct).
110
            // We ignore this case instead of throwing an exception - essentially disabling drop-in templates on systems
111
            // which contain an unexpected public path.
112
            if (strlen($templateFile) > $basePathLength
5✔
113
                && substr_compare($basePath, $templateFile, 0, $basePathLength)
5✔
114
            ) {
115
                $relativeTemplatePath = substr($templateFile, $basePathLength);
5✔
116
                $contentType = new DropInContentTypeDefinition(
5✔
117
                    'FluidTYPO3.Flux',
5✔
118
                    $contentTypesPath,
5✔
119
                    $relativeTemplatePath
5✔
120
                );
5✔
121
                $types[$contentType->getContentTypeName()] = $contentType;
5✔
122
            }
123
        }
124
        return $types;
5✔
125
    }
126

127
    public function getIconReference(): string
128
    {
129
        return '';
5✔
130
    }
131

132
    public function getProviderClassName(): ?string
133
    {
134
        return $this->providerClassName;
5✔
135
    }
136

137
    protected static function initializeDropInFileSystemStructure(string $basePath): void
138
    {
139
        if (!file_exists($basePath)) {
10✔
140
            static::createDir($basePath . static::PARTIALS_DIRECTORY);
5✔
141
            static::createDir(
5✔
142
                $basePath . static::LAYOUTS_DIRECTORY,
5✔
143
                ExtensionManagementUtility::extPath('flux', 'Resources/Private/Layouts/Default.html')
5✔
144
            );
5✔
145
            static::createDir(
5✔
146
                $basePath . static::TEMPLATES_DIRECTORY . static::CONTENT_DIRECTORY,
5✔
147
                ExtensionManagementUtility::extPath('flux', 'Resources/Private/Skeletons/Content/Standard.html')
5✔
148
            );
5✔
149
            static::createDir(
5✔
150
                $basePath . static::TEMPLATES_DIRECTORY . static::PAGE_DIRECTORY,
5✔
151
                ExtensionManagementUtility::extPath('flux', 'Resources/Private/Skeletons/Page/Standard.html')
5✔
152
            );
5✔
153
        }
154
    }
155

156
    protected static function createDir(string $directory, ?string $sourceFile = null): void
157
    {
158
        mkdir($directory, 0775, true);
5✔
159
        if ($sourceFile) {
5✔
160
            copy(
5✔
161
                $sourceFile,
5✔
162
                $directory . pathinfo($sourceFile, PATHINFO_BASENAME)
5✔
163
            );
5✔
164
        }
165
    }
166

167
    protected static function determineAbsolutePathForFilename(string $filename): string
168
    {
169
        if (strpos($filename, '://') !== false) {
15✔
170
            return $filename;
10✔
171
        }
172
        if (strpos($filename, '/') === 0) {
5✔
173
            return $filename;
5✔
174
        }
175
        return Environment::getPublicPath() . '/' . $filename;
×
176
    }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc