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

FluidTYPO3 / vhs / 13566190336

27 Feb 2025 12:18PM UTC coverage: 72.127% (-0.6%) from 72.746%
13566190336

push

github

NamelessCoder
[TER] 7.1.0

5649 of 7832 relevant lines covered (72.13%)

20.01 hits per line

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

88.46
/Classes/ViewHelpers/Resource/Record/FalViewHelper.php
1
<?php
2
namespace FluidTYPO3\Vhs\ViewHelpers\Resource\Record;
3

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

11
use FluidTYPO3\Vhs\Proxy\DoctrineQueryProxy;
12
use FluidTYPO3\Vhs\Proxy\FileRepositoryProxy;
13
use FluidTYPO3\Vhs\Proxy\ResourceFactoryProxy;
14
use FluidTYPO3\Vhs\Utility\ResourceUtility;
15
use TYPO3\CMS\Core\Database\Connection;
16
use TYPO3\CMS\Core\Database\ConnectionPool;
17
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
18
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
19
use TYPO3\CMS\Core\Resource\FileReference;
20
use TYPO3\CMS\Core\Utility\ArrayUtility;
21
use TYPO3\CMS\Core\Utility\GeneralUtility;
22
use TYPO3\CMS\Core\Versioning\VersionState;
23

24
/**
25
 * Resolve FAL relations and return file records.
26
 *
27
 * ### Render a single image linked from a TCA record
28
 *
29
 * We assume that the table `tx_users` has a column `photo`, which is a FAL
30
 * relation field configured with
31
 * [`ExtensionManagementUtility::getFileFieldTCAConfig()`]
32
 * (https://docs.typo3.org/typo3cms/TCAReference/Reference/Columns/Inline/Index.html#file-abstraction-layer).
33
 * The template also has a `user` variable containing one of the table's
34
 * records.
35
 *
36
 * At first, fetch the record and store it in a variable.
37
 * Then use `<f:image>` to render it:
38
 *
39
 * ```
40
 * {v:resource.record.fal(table: 'tx_users', field: 'photo', record: user)
41
 *  -> v:iterator.first()
42
 *  -> v:variable.set(name: 'image')}
43
 * <f:if condition="{image}">
44
 *   <f:image treatIdAsReference="1" src="{image.id}" title="{image.title}" alt="{image.alternative}"/>
45
 * </f:if>
46
 * ```
47
 *
48
 * Use the `uid` attribute if you don't have a `record`.
49
 */
50
class FalViewHelper extends AbstractRecordResourceViewHelper
51
{
52
    /**
53
     * @var ResourceFactoryProxy
54
     */
55
    protected $resourceFactory;
56

57
    /**
58
     * @var FileRepositoryProxy
59
     */
60
    protected $fileRepository;
61

62
    /**
63
     * @var boolean
64
     */
65
    protected $escapeOutput = false;
66

67
    /**
68
     * Constructor
69
     */
70
    public function __construct()
71
    {
72
        /** @var ResourceFactoryProxy $resourceFactory */
73
        $resourceFactory = GeneralUtility::makeInstance(ResourceFactoryProxy::class);
28✔
74
        $this->resourceFactory = $resourceFactory;
28✔
75
        /** @var FileRepositoryProxy $fileRepository */
76
        $fileRepository = GeneralUtility::makeInstance(FileRepositoryProxy::class);
28✔
77
        $this->fileRepository = $fileRepository;
28✔
78
    }
79

80
    public function initializeArguments(): void
81
    {
82
        parent::initializeArguments();
21✔
83
        $this->registerArgument(
21✔
84
            'asObjects',
21✔
85
            'bool',
21✔
86
            'Can be set to TRUE to return objects instead of file information arrays.',
21✔
87
            false,
21✔
88
            false
21✔
89
        );
21✔
90
    }
91

92
    /**
93
     * @param FileReference $fileReference
94
     * @return array
95
     */
96
    public function getResource($fileReference)
97
    {
98
        $file = $fileReference->getOriginalFile();
7✔
99
        $fileReferenceProperties = $fileReference->getProperties();
7✔
100
        $fileProperties = ResourceUtility::getFileArray($file);
7✔
101
        ArrayUtility::mergeRecursiveWithOverrule($fileProperties, $fileReferenceProperties, true, true, false);
7✔
102
        return $fileProperties;
7✔
103
    }
104

105
    /**
106
     * @param array|integer $uidOrRecord Database row
107
     */
108
    protected function getFileReferences(string $table, string $field, $uidOrRecord): array
109
    {
110
        if (is_array($uidOrRecord)) {
7✔
111
            $record = $uidOrRecord;
7✔
112
        } else {
113
            $record = $this->getRecord($uidOrRecord);
×
114
            if (!is_array($record)) {
×
115
                return [];
×
116
            }
117
        }
118

119
        if (isset($record['t3ver_oid']) && (integer) $record['t3ver_oid'] !== 0) {
7✔
120
            $sqlRecordUid = $record['t3ver_oid'];
×
121
        } elseif (isset($record['_LOCALIZED_UID'])) {
7✔
122
            $sqlRecordUid = $record['_LOCALIZED_UID'];
×
123
        } elseif (isset($record['_PAGES_OVERLAY_UID'])) {
7✔
124
            $sqlRecordUid = $record['_PAGES_OVERLAY_UID'];
×
125
        } else {
126
            $sqlRecordUid = $record[$this->idField];
7✔
127
        }
128
        $fileObjects = $this->fileRepository->findByRelation($table, $field, $sqlRecordUid);
7✔
129
        return $fileObjects;
7✔
130
    }
131

132
    public function getResources(array $record): array
133
    {
134
        if (empty($record)) {
35✔
135
            return [];
14✔
136
        }
137
        if (!empty($GLOBALS['TSFE']->sys_page)) {
21✔
138
            $fileReferences = $this->getFileReferences($this->getTable(), $this->getField(), $record);
7✔
139
        } else {
140
            if (isset($record['t3ver_oid']) && (integer) $record['t3ver_oid'] !== 0) {
14✔
141
                $sqlRecordUid = $record['t3ver_oid'];
×
142
            } elseif (isset($record['_LOCALIZED_UID'])) {
14✔
143
                $sqlRecordUid = $record['_LOCALIZED_UID'];
×
144
            } elseif (isset($record['_PAGES_OVERLAY_UID'])) {
14✔
145
                $sqlRecordUid = $record['_PAGES_OVERLAY_UID'];
×
146
            } else {
147
                $sqlRecordUid = $record[$this->idField];
14✔
148
            }
149

150
            /** @var ConnectionPool $connectionPool */
151
            $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
14✔
152
            /** @var QueryBuilder $queryBuilder */
153
            $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_file_reference');
14✔
154

155
            $queryBuilder->createNamedParameter($this->getTable(), Connection::PARAM_STR, ':tablenames');
14✔
156
            $queryBuilder->createNamedParameter($sqlRecordUid, Connection::PARAM_INT, ':uid_foreign');
14✔
157
            $queryBuilder->createNamedParameter($this->getField(), Connection::PARAM_STR, ':fieldname');
14✔
158

159
            $queryBuilder
14✔
160
                ->select('uid')
14✔
161
                ->from('sys_file_reference')
14✔
162
                ->where(
14✔
163
                    $queryBuilder->expr()->eq('tablenames', ':tablenames')
14✔
164
                )
14✔
165
                ->andWhere(
14✔
166
                    $queryBuilder->expr()->eq('uid_foreign', ':uid_foreign')
14✔
167
                )
14✔
168
                ->andWhere(
14✔
169
                    $queryBuilder->expr()->eq('fieldname', ':fieldname')
14✔
170
                );
14✔
171

172
            if ($GLOBALS['BE_USER']->workspaceRec['uid']) {
14✔
173
                $queryBuilder->createNamedParameter(
7✔
174
                    $GLOBALS['BE_USER']->workspaceRec['uid'],
7✔
175
                    Connection::PARAM_INT,
7✔
176
                    ':t3ver_wsid'
7✔
177
                );
7✔
178
                $queryBuilder
7✔
179
                    ->andWhere(
7✔
180
                        $queryBuilder->expr()->eq('deleted', 0)
7✔
181
                    )
7✔
182
                    ->andWhere(
7✔
183
                        $queryBuilder->expr()->eq('t3ver_wsid', 0)
7✔
184
                        . ' OR ' .
7✔
185
                        $queryBuilder->expr()->eq('t3ver_wsid', ':t3ver_wsid')
7✔
186
                    )
7✔
187
                    ->andWhere(
7✔
188
                        $queryBuilder->expr()->neq('pid', -1)
7✔
189
                    );
7✔
190
            } else {
191
                $queryBuilder
7✔
192
                    ->andWhere(
7✔
193
                        $queryBuilder->expr()->eq('deleted', 0)
7✔
194
                    )
7✔
195
                    ->andWhere(
7✔
196
                        $queryBuilder->expr()->lte('t3ver_state', 0)
7✔
197
                    )
7✔
198
                    ->andWhere(
7✔
199
                        $queryBuilder->expr()->neq('pid', -1)
7✔
200
                    )
7✔
201
                    ->andWhere(
7✔
202
                        $queryBuilder->expr()->eq('hidden', 0)
7✔
203
                    );
7✔
204
            }
205

206
            $queryBuilder->orderBy('sorting_foreign');
14✔
207

208
            // Execute
209
            $statement = DoctrineQueryProxy::executeQueryOnQueryBuilder($queryBuilder);
14✔
210
            /** @var array[] $references */
211
            $references = DoctrineQueryProxy::fetchAllAssociative($statement);
14✔
212

213
            $fileReferences = [];
14✔
214

215
            foreach ($references as $reference) {
14✔
216
                try {
217
                    // Just passing the reference uid, the factory is doing workspace
218
                    // overlays automatically depending on the current environment
219
                    $fileReferences[] = $this->resourceFactory->getFileReferenceObject($reference['uid'] ?? 0);
14✔
220
                } catch (ResourceDoesNotExistException $exception) {
×
221
                    // No handling, just omit the invalid reference uid
222
                    continue;
×
223
                }
224
            }
225
        }
226
        $resources = [];
21✔
227
        foreach ($fileReferences as $file) {
21✔
228
            // Exclude workspace deleted files references
229
            if ($file->getProperty('t3ver_state') !== VersionState::DELETE_PLACEHOLDER) {
14✔
230
                try {
231
                    $resources[] = $this->arguments['asObjects'] ? $file : $this->getResource($file);
14✔
232
                } catch (\InvalidArgumentException $error) {
×
233
                    // Pokemon-style, catch-all and suppress. This exception type is thrown if a file gets removed.
234
                }
235
            }
236
        }
237
        return $resources;
21✔
238
    }
239
}
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