TemporaryFileEventListener.php (7053B)
1 <?php 2 3 namespace PartKeepr\UploadedFileBundle\EventListener; 4 5 use Doctrine\Common\Annotations\Reader; 6 use Dunglas\ApiBundle\Api\IriConverterInterface; 7 use PartKeepr\ImageBundle\Entity\Image; 8 use PartKeepr\ImageBundle\Entity\TempImage; 9 use PartKeepr\ImageBundle\Services\ImageService; 10 use PartKeepr\UploadedFileBundle\Entity\TempUploadedFile; 11 use PartKeepr\UploadedFileBundle\Entity\UploadedFile; 12 use PartKeepr\UploadedFileBundle\Services\UploadedFileService; 13 use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent; 14 use Symfony\Component\PropertyAccess\PropertyAccessorInterface; 15 16 class TemporaryFileEventListener 17 { 18 /** 19 * @var UploadedFileService 20 */ 21 private $uploadedFileService; 22 23 /** 24 * @var ImageService 25 */ 26 private $imageService; 27 28 /** 29 * @var Reader 30 */ 31 private $reader; 32 33 /** 34 * @var PropertyAccessorInterface 35 */ 36 private $propertyAccessor; 37 38 /** 39 * @var IriConverterInterface 40 */ 41 private $iriConverter; 42 43 public function __construct( 44 UploadedFileService $uploadedFileService, 45 ImageService $imageService, 46 Reader $reader, 47 PropertyAccessorInterface $propertyAccessor, 48 IriConverterInterface $iriConverter 49 ) { 50 $this->uploadedFileService = $uploadedFileService; 51 $this->imageService = $imageService; 52 $this->reader = $reader; 53 $this->propertyAccessor = $propertyAccessor; 54 $this->iriConverter = $iriConverter; 55 } 56 57 /** 58 * Replaces any temporary images with actual instances of the configured UploadedFile collection. 59 * 60 * Automatically extracts the proper setters and getters from the metadata and instantiates the correct 61 * UploadedFile child class. 62 * 63 * @param GetResponseForControllerResultEvent $event The event 64 */ 65 public function replaceTemporaryFile(GetResponseForControllerResultEvent $event) 66 { 67 $data = $event->getControllerResult(); 68 69 if (!is_object($data)) { 70 return; 71 } 72 73 $classReflection = new \ReflectionClass($data); 74 75 foreach ($classReflection->getProperties() as $property) { 76 $propertyAnnotationCollection = $this->reader->getPropertyAnnotation( 77 $property, 78 'PartKeepr\UploadedFileBundle\Annotation\UploadedFileCollection' 79 ); 80 81 $propertyAnnotation = $this->reader->getPropertyAnnotation( 82 $property, 83 'PartKeepr\UploadedFileBundle\Annotation\UploadedFile' 84 ); 85 86 $manyToOneAnnotation = $this->reader->getPropertyAnnotation( 87 $property, 88 'Doctrine\ORM\Mapping\OneToMany' 89 ); 90 91 $oneToOneAnnotation = $this->reader->getPropertyAnnotation( 92 $property, 93 'Doctrine\ORM\Mapping\OneToOne' 94 ); 95 96 if ($propertyAnnotationCollection !== null || $propertyAnnotation !== null) { 97 if ($manyToOneAnnotation !== null) { 98 $collection = $this->propertyAccessor->getValue($data, $property->getName()); 99 100 foreach ($collection as $key => $item) { 101 if ($item instanceof TempUploadedFile || $item instanceof TempImage) { 102 $targetEntity = $manyToOneAnnotation->targetEntity; 103 104 $newFile = $this->setReplacementFile($targetEntity, $item, $data); 105 $collection[$key] = $newFile; 106 } 107 } 108 109 $this->propertyAccessor->setValue($data, $property->getName(), $collection); 110 } 111 112 if ($oneToOneAnnotation !== null) { 113 $item = $this->propertyAccessor->getValue($data, $property->getName()); 114 115 if ($item instanceof TempUploadedFile || $item instanceof TempImage) { 116 $targetEntity = $oneToOneAnnotation->targetEntity; 117 118 $newFile = $this->setReplacementFile($targetEntity, $item, $data); 119 120 $this->propertyAccessor->setValue($data, $property->getName(), $newFile); 121 } else { 122 $item = $this->propertyAccessor->getValue($data, $property->getName()); 123 124 if ($item !== null && $item->getReplacement() !== null) { 125 /** 126 * @var UploadedFile 127 */ 128 $tempImage = $this->iriConverter->getItemFromIri($item->getReplacement()); 129 $this->replaceFile($item, $tempImage); 130 } 131 } 132 } 133 } 134 } 135 136 $event->setControllerResult($data); 137 } 138 139 /** 140 * Replaces the TemporaryUploadedFile or TempImage with the actual instance. Automatically sets the 141 * reference to the owning entity. 142 * 143 * @param string $targetEntity The entity to create 144 * @param TempUploadedFile|TempImage $source The source entity 145 * @param object $target The entity where to set the property 146 * 147 * @return object The newly created object instance 148 */ 149 protected function setReplacementFile($targetEntity, $source, $target) 150 { 151 /** 152 * @var UploadedFile 153 */ 154 $newFile = new $targetEntity(); 155 156 $this->replaceFile($newFile, $source); 157 158 $setterName = $this->getReferenceSetter($newFile, $target); 159 160 if ($setterName !== false) { 161 $this->propertyAccessor->setValue($newFile, $setterName, $target); 162 } 163 164 return $newFile; 165 } 166 167 protected function replaceFile(UploadedFile $target, UploadedFile $source) 168 { 169 if ($target instanceof Image) { 170 $this->imageService->replaceFromUploadedFile($target, $source); 171 } else { 172 $this->uploadedFileService->replaceFromUploadedFile($target, $source); 173 } 174 $target->setDescription($source->getDescription()); 175 } 176 177 /** 178 * Returns the setter name for the inverse side. 179 * 180 * @param $inverseSideEntity 181 * @param $owningSideEntity 182 * 183 * @return bool|string 184 */ 185 protected function getReferenceSetter($inverseSideEntity, $owningSideEntity) 186 { 187 $inverseSideReflection = new \ReflectionClass($inverseSideEntity); 188 $owningSideReflection = new \ReflectionClass($owningSideEntity); 189 190 foreach ($inverseSideReflection->getProperties() as $inverseSideProperty) { 191 $oneToManyAssociation = $this->reader->getPropertyAnnotation( 192 $inverseSideProperty, 193 'Doctrine\ORM\Mapping\ManyToOne' 194 ); 195 196 if ($oneToManyAssociation !== null && 197 $oneToManyAssociation->targetEntity == $owningSideReflection->getName() 198 ) { 199 return $inverseSideProperty->getName(); 200 } 201 } 202 203 return false; 204 } 205 }