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

FluidTYPO3 / vhs / 13014187021

28 Jan 2025 03:46PM UTC coverage: 71.952% (+0.08%) from 71.877%
13014187021

push

github

NamelessCoder
[TASK] Make tests run on v13

5636 of 7833 relevant lines covered (71.95%)

17.17 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);
24✔
74
        $this->resourceFactory = $resourceFactory;
24✔
75
        /** @var FileRepositoryProxy $fileRepository */
76
        $fileRepository = GeneralUtility::makeInstance(FileRepositoryProxy::class);
24✔
77
        $this->fileRepository = $fileRepository;
24✔
78
    }
79

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

92
    /**
93
     * @param FileReference $fileReference
94
     * @return array
95
     */
96
    public function getResource($fileReference)
97
    {
98
        $file = $fileReference->getOriginalFile();
6✔
99
        $fileReferenceProperties = $fileReference->getProperties();
6✔
100
        $fileProperties = ResourceUtility::getFileArray($file);
6✔
101
        ArrayUtility::mergeRecursiveWithOverrule($fileProperties, $fileReferenceProperties, true, true, false);
6✔
102
        return $fileProperties;
6✔
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)) {
6✔
111
            $record = $uidOrRecord;
6✔
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) {
6✔
120
            $sqlRecordUid = $record['t3ver_oid'];
×
121
        } elseif (isset($record['_LOCALIZED_UID'])) {
6✔
122
            $sqlRecordUid = $record['_LOCALIZED_UID'];
×
123
        } elseif (isset($record['_PAGES_OVERLAY_UID'])) {
6✔
124
            $sqlRecordUid = $record['_PAGES_OVERLAY_UID'];
×
125
        } else {
126
            $sqlRecordUid = $record[$this->idField];
6✔
127
        }
128
        $fileObjects = $this->fileRepository->findByRelation($table, $field, $sqlRecordUid);
6✔
129
        return $fileObjects;
6✔
130
    }
131

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

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

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

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

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

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

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

213
            $fileReferences = [];
12✔
214

215
            foreach ($references as $reference) {
12✔
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);
12✔
220
                } catch (ResourceDoesNotExistException $exception) {
×
221
                    // No handling, just omit the invalid reference uid
222
                    continue;
×
223
                }
224
            }
225
        }
226
        $resources = [];
18✔
227
        foreach ($fileReferences as $file) {
18✔
228
            // Exclude workspace deleted files references
229
            if ($file->getProperty('t3ver_state') !== VersionState::DELETE_PLACEHOLDER) {
12✔
230
                try {
231
                    $resources[] = $this->arguments['asObjects'] ? $file : $this->getResource($file);
12✔
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;
18✔
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