1 | <?php |
||
2 | declare(strict_types=1); |
||
3 | |||
4 | namespace SourceBroker\T3api\Serializer\Handler; |
||
5 | |||
6 | use JMS\Serializer\DeserializationContext; |
||
7 | use JMS\Serializer\JsonDeserializationVisitor; |
||
8 | use JMS\Serializer\SerializationContext; |
||
9 | use JMS\Serializer\Visitor\DeserializationVisitorInterface; |
||
10 | use JMS\Serializer\Visitor\SerializationVisitorInterface; |
||
11 | use RuntimeException; |
||
12 | use SourceBroker\T3api\Exception\ValidationException; |
||
13 | use SourceBroker\T3api\Service\SerializerService; |
||
14 | use TYPO3\CMS\Core\Resource\FileReference as Typo3FileReference; |
||
15 | use TYPO3\CMS\Core\Resource\Rendering\RendererRegistry; |
||
16 | use TYPO3\CMS\Core\Resource\ResourceFactory; |
||
17 | use TYPO3\CMS\Extbase\Domain\Model\AbstractFileFolder; |
||
18 | use TYPO3\CMS\Extbase\Domain\Model\FileReference as ExtbaseFileReference; |
||
19 | use TYPO3\CMS\Extbase\DomainObject\AbstractDomainObject; |
||
20 | use TYPO3\CMS\Extbase\Error\Error; |
||
21 | use TYPO3\CMS\Extbase\Error\Result; |
||
22 | use TYPO3\CMS\Extbase\Object\ObjectManager; |
||
23 | use TYPO3\CMS\Extbase\Persistence\Generic\PersistenceManager; |
||
24 | use TYPO3\CMS\Extbase\Reflection\ObjectAccess; |
||
25 | |||
26 | /** |
||
27 | * Class FileReferenceHandler |
||
28 | */ |
||
29 | class FileReferenceHandler extends AbstractHandler implements SerializeHandlerInterface, DeserializeHandlerInterface |
||
30 | { |
||
31 | public const TYPE = 'FileReferenceTransport'; |
||
32 | |||
33 | /** |
||
34 | * @var string[] |
||
35 | */ |
||
36 | protected static $supportedTypes = [self::TYPE]; |
||
37 | |||
38 | /** |
||
39 | * @var ResourceFactory |
||
40 | */ |
||
41 | protected $resourceFactory; |
||
42 | |||
43 | /** |
||
44 | * @var ObjectManager |
||
45 | */ |
||
46 | protected $objectManager; |
||
47 | |||
48 | /** |
||
49 | * @var PersistenceManager |
||
50 | */ |
||
51 | protected $persistenceManager; |
||
52 | |||
53 | /** |
||
54 | * @var SerializerService |
||
55 | */ |
||
56 | protected $serializerService; |
||
57 | |||
58 | /** |
||
59 | * @param ResourceFactory $resourceFactory |
||
60 | */ |
||
61 | public function injectResourceFactory(ResourceFactory $resourceFactory): void |
||
62 | { |
||
63 | $this->resourceFactory = $resourceFactory; |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * @param ObjectManager $objectManager |
||
68 | */ |
||
69 | public function injectObjectManager(ObjectManager $objectManager): void |
||
70 | { |
||
71 | $this->objectManager = $objectManager; |
||
72 | } |
||
73 | |||
74 | /** |
||
75 | * @param PersistenceManager $persistenceManager |
||
76 | */ |
||
77 | public function injectPersistenceManager(PersistenceManager $persistenceManager): void |
||
78 | { |
||
79 | $this->persistenceManager = $persistenceManager; |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @param SerializerService $serializerService |
||
84 | */ |
||
85 | public function injectSerializerService(SerializerService $serializerService): void |
||
86 | { |
||
87 | $this->serializerService = $serializerService; |
||
88 | } |
||
89 | |||
90 | /** |
||
91 | * @param SerializationVisitorInterface $visitor |
||
92 | * @param ExtbaseFileReference|Typo3FileReference $fileReference |
||
93 | * @param array $type |
||
94 | * @param SerializationContext $context |
||
95 | * |
||
96 | * @return array |
||
97 | * |
||
98 | * @todo Try to implement it with default JMS serialization functionality instead of using this handler |
||
99 | */ |
||
100 | public function serialize( |
||
101 | SerializationVisitorInterface $visitor, |
||
102 | $fileReference, |
||
103 | array $type, |
||
104 | SerializationContext $context |
||
105 | ): array { |
||
106 | /** @var Typo3FileReference $originalResource */ |
||
107 | $originalResource = $fileReference instanceof ExtbaseFileReference |
||
108 | ? $fileReference->getOriginalResource() |
||
109 | : $fileReference; |
||
110 | $originalFile = $originalResource->getOriginalFile(); |
||
111 | |||
112 | $url = $originalResource->getPublicUrl(); |
||
113 | if (parse_url($url, PHP_URL_SCHEME) === null) { |
||
114 | $url = $context->getAttribute('TYPO3_SITE_URL') . $url; |
||
115 | } |
||
116 | |||
117 | $out = [ |
||
118 | 'uid' => $fileReference->getUid(), |
||
119 | 'url' => $url, |
||
120 | 'file' => [ |
||
121 | 'uid' => $originalFile->getUid(), |
||
122 | 'name' => $originalFile->getName(), |
||
123 | 'mimeType' => $originalFile->getMimeType(), |
||
124 | 'size' => $originalFile->getSize(), |
||
125 | ], |
||
126 | ]; |
||
127 | |||
128 | // TODO: move to some signal/slot |
||
129 | if (preg_match('#video/.*#', $originalFile->getMimeType())) { |
||
130 | $fileRenderer = RendererRegistry::getInstance()->getRenderer($originalFile); |
||
131 | if ($fileRenderer !== null && preg_match( |
||
132 | '/src="([^"]+)"/', |
||
133 | $fileRenderer->render($originalFile, 1, 1), |
||
134 | $match |
||
135 | )) { |
||
136 | $urlEmbed = $match[1]; |
||
137 | if (parse_url($urlEmbed, PHP_URL_SCHEME) === null) { |
||
138 | $urlEmbed = $context->getAttribute('TYPO3_SITE_URL') . $urlEmbed; |
||
139 | } |
||
140 | $out['urlEmbed'] = $urlEmbed; |
||
141 | } |
||
142 | } |
||
143 | |||
144 | return $out; |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * @param DeserializationVisitorInterface $visitor |
||
149 | * @param mixed $data |
||
150 | * @param array $type |
||
151 | * @param DeserializationContext $context |
||
152 | * @throws ValidationException |
||
153 | * @return mixed|void |
||
154 | */ |
||
155 | public function deserialize( |
||
156 | DeserializationVisitorInterface $visitor, |
||
157 | $data, |
||
158 | array $type, |
||
159 | DeserializationContext $context |
||
160 | ) { |
||
161 | if ($type['name'] !== self::TYPE) { |
||
162 | throw new RuntimeException(sprintf('`%s` is unknown type.', $type['name']), 1577534783745); |
||
163 | } |
||
164 | |||
165 | if (empty($type['params']['targetType'])) { |
||
166 | throw new RuntimeException('`targetType` is required parameter.', 1577534803669); |
||
167 | } |
||
168 | |||
169 | if (!is_subclass_of($type['params']['targetType'], AbstractFileFolder::class)) { |
||
170 | throw new RuntimeException( |
||
171 | sprintf('Has to be an instance of `%s` to be processed', AbstractFileFolder::class), |
||
172 | 1577534838461 |
||
173 | ); |
||
174 | } |
||
175 | |||
176 | if ($data === 0) { |
||
177 | $this->removeExistingFileReference($context); |
||
178 | |||
179 | return null; |
||
180 | } |
||
181 | |||
182 | $isNew = is_array($data) && empty($data['uid']); |
||
183 | |||
184 | if ($isNew) { |
||
185 | return $this->createSysFileReference($data, $type['params']['targetType'], $context); |
||
186 | } |
||
187 | |||
188 | $uid = (int)(is_numeric($data) ? $data : $data['uid']); |
||
189 | |||
190 | if ($uid) { |
||
191 | return $this->persistenceManager->getObjectByIdentifier( |
||
192 | $uid, |
||
193 | ExtbaseFileReference::class, |
||
194 | false |
||
195 | ); |
||
196 | } |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @param array $data |
||
201 | * @param string $type |
||
202 | * @param DeserializationContext $context |
||
203 | * @throws ValidationException |
||
204 | * @return ExtbaseFileReference |
||
205 | */ |
||
206 | protected function createSysFileReference( |
||
207 | array $data, |
||
208 | string $type, |
||
209 | DeserializationContext $context |
||
210 | ): ExtbaseFileReference { |
||
211 | /** @var JsonDeserializationVisitor $visitor */ |
||
212 | $visitor = $context->getVisitor(); |
||
213 | |||
214 | if (empty($data['uidLocal'])) { |
||
215 | $result = new Result(); |
||
216 | $result->forProperty('uidLocal')->addError( |
||
217 | new Error('Property `uidLocal` is required to create sys file reference', 1577083636258) |
||
218 | ); |
||
219 | |||
220 | throw new ValidationException($result, 1581461062805); |
||
221 | } |
||
222 | |||
223 | $this->removeExistingFileReference($context); |
||
224 | |||
225 | /** @var ExtbaseFileReference $fileReference */ |
||
226 | $fileReference = $this->serializerService->deserialize( |
||
227 | json_encode($data), |
||
228 | $type, |
||
229 | $this->cloneDeserializationContext($context, ['target' => null]) |
||
230 | ); |
||
231 | |||
232 | $fileReference->setOriginalResource( |
||
233 | $this->resourceFactory->createFileReferenceObject( |
||
234 | [ |
||
235 | 'uid_local' => $data['uidLocal'], |
||
236 | 'uid' => uniqid('NEW_', true), |
||
237 | ] |
||
238 | ) |
||
239 | ); |
||
240 | |||
241 | if ($visitor->getCurrentObject() instanceof AbstractDomainObject) { |
||
242 | /** @var AbstractDomainObject $currentObject */ |
||
243 | $currentObject = $visitor->getCurrentObject(); |
||
244 | $fileReference->setPid($currentObject->getPid()); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
245 | $fileReference->_setProperty('_languageUid', $currentObject->_getProperty('_languageUid')); |
||
246 | } |
||
247 | |||
248 | return $fileReference; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Removes already existing file reference if property is not a collection but relation to single file |
||
253 | * |
||
254 | * @param DeserializationContext $context |
||
255 | */ |
||
256 | protected function removeExistingFileReference(DeserializationContext $context): void |
||
257 | { |
||
258 | /** @var JsonDeserializationVisitor $visitor */ |
||
259 | $visitor = $context->getVisitor(); |
||
260 | $propertyName = $context->getCurrentPath()[count($context->getCurrentPath()) - 1]; |
||
261 | $propertyValue = ObjectAccess::getProperty($visitor->getCurrentObject(), $propertyName); |
||
262 | if ($propertyValue instanceof ExtbaseFileReference || $propertyValue instanceof Typo3FileReference) { |
||
263 | $this->persistenceManager->remove($propertyValue); |
||
264 | } |
||
265 | } |
||
266 | } |
||
267 |