TYPO3 CMS  TYPO3_7-6
ProcessedFile.php
Go to the documentation of this file.
1 <?php
3 
4 /*
5  * This file is part of the TYPO3 CMS project.
6  *
7  * It is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License, either version 2
9  * of the License, or any later version.
10  *
11  * For the full copyright and license information, please read the
12  * LICENSE.txt file that was distributed with this source code.
13  *
14  * The TYPO3 project - inspiring people to share!
15  */
16 
18 
41 {
42  /*********************************************
43  * FILE PROCESSING CONTEXTS
44  *********************************************/
49  const CONTEXT_IMAGEPREVIEW = 'Image.Preview';
55  const CONTEXT_IMAGECROPSCALEMASK = 'Image.CropScaleMask';
56 
62  protected $taskType;
63 
67  protected $task;
68 
72  protected $taskTypeRegistry;
73 
80 
86  protected $originalFile;
87 
95  protected $originalFileSha1;
96 
103  protected $updated = false;
104 
114  public function __construct(File $originalFile, $taskType, array $processingConfiguration, array $databaseRow = null)
115  {
116  $this->originalFile = $originalFile;
117  $this->originalFileSha1 = $this->originalFile->getSha1();
118  $this->storage = $originalFile->getStorage()->getProcessingFolder()->getStorage();
119  $this->taskType = $taskType;
120  $this->processingConfiguration = $processingConfiguration;
121  if (is_array($databaseRow)) {
122  $this->reconstituteFromDatabaseRecord($databaseRow);
123  }
124  $this->taskTypeRegistry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Resource\Processing\TaskTypeRegistry::class);
125  }
126 
133  protected function reconstituteFromDatabaseRecord(array $databaseRow)
134  {
135  $this->taskType = $this->taskType ?: $databaseRow['task_type'];
136  $this->processingConfiguration = $this->processingConfiguration ?: unserialize($databaseRow['configuration']);
137 
138  $this->originalFileSha1 = $databaseRow['originalfilesha1'];
139  $this->identifier = $databaseRow['identifier'];
140  $this->name = $databaseRow['name'];
141  $this->properties = $databaseRow;
142  }
143 
144  /********************************
145  * VARIOUS FILE PROPERTY GETTERS
146  ********************************/
147 
153  // @todo replace these usages with direct calls to the task object
154  public function calculateChecksum()
155  {
156  return $this->getTask()->getConfigurationChecksum();
157  }
158 
159  /*******************
160  * CONTENTS RELATED
161  *******************/
169  public function setContents($contents)
170  {
171  throw new \BadMethodCallException('Setting contents not possible for processed file.', 1305438528);
172  }
173 
181  public function updateWithLocalFile($filePath)
182  {
183  if ($this->identifier === null) {
184  throw new \RuntimeException('Cannot update original file!', 1350582054);
185  }
186  $processingFolder = $this->originalFile->getStorage()->getProcessingFolder($this->originalFile);
187  $addedFile = $this->storage->updateProcessedFile($filePath, $this, $processingFolder);
188 
189  // Update some related properties
190  $this->identifier = $addedFile->getIdentifier();
191  $this->originalFileSha1 = $this->originalFile->getSha1();
192  $this->updateProperties($addedFile->getProperties());
193  $this->deleted = false;
194  $this->updated = true;
195  }
196 
197  /*****************************************
198  * STORAGE AND MANAGEMENT RELATED METHDOS
199  *****************************************/
205  public function isIndexed()
206  {
207  // Processed files are never indexed; instead you might be looking for isPersisted()
208  return false;
209  }
210 
216  public function isPersisted()
217  {
218  return is_array($this->properties) && array_key_exists('uid', $this->properties) && $this->properties['uid'] > 0;
219  }
220 
226  public function isNew()
227  {
228  return !$this->isPersisted();
229  }
230 
237  public function isUpdated()
238  {
239  return $this->updated;
240  }
241 
247  public function setName($name)
248  {
249  // Remove the existing file
250  if ($this->name !== $name && $this->name !== '' && $this->exists()) {
251  $this->delete();
252  }
253 
254  $this->name = $name;
255  // @todo this is a *weird* hack that will fail if the storage is non-hierarchical!
256  $this->identifier = $this->storage->getProcessingFolder($this->originalFile)->getIdentifier() . $this->name;
257 
258  $this->updated = true;
259  }
260 
261  /******************
262  * SPECIAL METHODS
263  ******************/
264 
270  public function isProcessed()
271  {
272  return $this->updated || ($this->isPersisted() && !$this->needsReprocessing());
273  }
274 
280  public function getOriginalFile()
281  {
282  return $this->originalFile;
283  }
284 
294  public function getIdentifier()
295  {
296  return (!$this->usesOriginalFile()) ? $this->identifier : $this->getOriginalFile()->getIdentifier();
297  }
298 
308  public function getName()
309  {
310  if ($this->usesOriginalFile()) {
311  return $this->originalFile->getName();
312  } else {
313  return $this->name;
314  }
315  }
316 
323  public function updateProperties(array $properties)
324  {
325  if (!is_array($this->properties)) {
326  $this->properties = [];
327  }
328 
329  if (array_key_exists('uid', $properties) && \TYPO3\CMS\Core\Utility\MathUtility::canBeInterpretedAsInteger($properties['uid'])) {
330  $this->properties['uid'] = $properties['uid'];
331  }
332 
333  // @todo we should have a blacklist of properties that might not be updated
334  $this->properties = array_merge($this->properties, $properties);
335 
336  // @todo when should this update be done?
337  if (!$this->isUnchanged() && $this->exists()) {
338  $this->properties = array_merge($this->properties, $this->storage->getFileInfo($this));
339  }
340  }
341 
347  public function toArray()
348  {
349  if ($this->usesOriginalFile()) {
350  $properties = $this->originalFile->getProperties();
351  unset($properties['uid']);
352  unset($properties['pid']);
353  unset($properties['identifier']);
354  unset($properties['name']);
355 
356  // Use width + height set in processed file
357  $properties['width'] = $this->properties['width'];
358  $properties['height'] = $this->properties['height'];
359  } else {
361  $properties['identifier'] = $this->getIdentifier();
362  $properties['name'] = $this->getName();
363  }
364 
365  $properties['configuration'] = serialize($this->processingConfiguration);
366 
367  return array_merge($properties, [
368  'storage' => $this->getStorage()->getUid(),
369  'checksum' => $this->calculateChecksum(),
370  'task_type' => $this->taskType,
371  'configurationsha1' => sha1($properties['configuration']),
372  'original' => $this->originalFile->getUid(),
373  'originalfilesha1' => $this->originalFileSha1
374  ]);
375  }
376 
382  protected function isUnchanged()
383  {
384  return !$this->properties['width'] && $this->usesOriginalFile();
385  }
386 
390  public function setUsesOriginalFile()
391  {
392  // @todo check if some of these properties can/should be set in a generic update method
393  $this->identifier = $this->originalFile->getIdentifier();
394  $this->updated = true;
395  $this->originalFileSha1 = $this->originalFile->getSha1();
396  }
397 
401  public function usesOriginalFile()
402  {
403  return $this->identifier == null || $this->identifier === $this->originalFile->getIdentifier();
404  }
405 
411  public function isOutdated()
412  {
413  return $this->needsReprocessing();
414  }
415 
422  public function delete($force = false)
423  {
424  if (!$force && $this->isUnchanged()) {
425  return false;
426  }
427  // Only delete file when original isn't used
428  if (!$this->usesOriginalFile()) {
429  return parent::delete();
430  }
431  return true;
432  }
433 
441  public function getProperty($key)
442  {
443  // The uid always (!) has to come from this file and never the original file (see getOriginalFile() to get this)
444  if ($this->isUnchanged() && $key !== 'uid') {
445  return $this->originalFile->getProperty($key);
446  } else {
447  return $this->properties[$key];
448  }
449  }
450 
456  public function getUid()
457  {
458  return $this->properties['uid'];
459  }
460 
466  public function needsReprocessing()
467  {
468  $fileMustBeRecreated = false;
469 
470  // if original is missing we can not reprocess the file
471  if ($this->originalFile->isMissing()) {
472  return false;
473  }
474 
475  // processedFile does not exist
476  if (!$this->usesOriginalFile() && !$this->exists()) {
477  $fileMustBeRecreated = true;
478  }
479 
480  // hash does not match
481  if (array_key_exists('checksum', $this->properties) && $this->calculateChecksum() !== $this->properties['checksum']) {
482  $fileMustBeRecreated = true;
483  }
484 
485  // original file changed
486  if ($this->originalFile->getSha1() !== $this->originalFileSha1) {
487  $fileMustBeRecreated = true;
488  }
489 
490  if (!array_key_exists('uid', $this->properties)) {
491  $fileMustBeRecreated = true;
492  }
493 
494  // remove outdated file
495  if ($fileMustBeRecreated && $this->exists()) {
496  $this->delete();
497  }
498  return $fileMustBeRecreated;
499  }
500 
506  public function getProcessingConfiguration()
507  {
509  }
510 
516  public function getTaskIdentifier()
517  {
518  return $this->taskType;
519  }
520 
527  public function getTask()
528  {
529  if ($this->task == null) {
530  $this->task = $this->taskTypeRegistry->getTaskForType($this->taskType, $this, $this->processingConfiguration);
531  }
532 
533  return $this->task;
534  }
535 
542  {
543  $name = $this->originalFile->getNameWithoutExtension();
544  $name .= '_' . $this->originalFile->getUid();
545  $name .= '_' . $this->calculateChecksum();
546 
547  return $name;
548  }
549 
556  public function getPublicUrl($relativeToCurrentScript = false)
557  {
558  if ($this->deleted) {
559  return null;
560  } elseif ($this->usesOriginalFile()) {
561  return $this->getOriginalFile()->getPublicUrl($relativeToCurrentScript);
562  } else {
563  return $this->getStorage()->getPublicUrl($this, $relativeToCurrentScript);
564  }
565  }
566 }
reconstituteFromDatabaseRecord(array $databaseRow)
getPublicUrl($relativeToCurrentScript=false)
__construct(File $originalFile, $taskType, array $processingConfiguration, array $databaseRow=null)