vendor/vich/uploader-bundle/src/Mapping/PropertyMapping.php line 180

Open in your IDE?
  1. <?php
  2. namespace Vich\UploaderBundle\Mapping;
  3. use Symfony\Component\HttpFoundation\File\File;
  4. use Symfony\Component\PropertyAccess\PropertyAccess;
  5. use Symfony\Component\PropertyAccess\PropertyAccessor;
  6. use Vich\UploaderBundle\Naming\DirectoryNamerInterface;
  7. use Vich\UploaderBundle\Naming\NamerInterface;
  8. /**
  9. * PropertyMapping.
  10. *
  11. * @author Dustin Dobervich <ddobervich@gmail.com>
  12. * @final
  13. */
  14. class PropertyMapping
  15. {
  16. /**
  17. * @var NamerInterface|null
  18. */
  19. protected $namer;
  20. /**
  21. * @var DirectoryNamerInterface
  22. */
  23. protected $directoryNamer;
  24. /**
  25. * @var array
  26. */
  27. protected $mapping;
  28. /**
  29. * @var string
  30. */
  31. protected $mappingName;
  32. /**
  33. * @var array<string, string|null>
  34. */
  35. protected $propertyPaths = [
  36. 'file' => null,
  37. 'name' => null,
  38. 'size' => null,
  39. 'mimeType' => null,
  40. 'originalName' => null,
  41. 'dimensions' => null,
  42. ];
  43. /**
  44. * @var PropertyAccessor
  45. */
  46. protected $accessor;
  47. /**
  48. * @param string $filePropertyPath The path to the "file" property
  49. * @param string $fileNamePropertyPath The path to the "filename" property
  50. * @param array|string[] $propertyPaths The paths to other properties
  51. */
  52. public function __construct(string $filePropertyPath, string $fileNamePropertyPath, array $propertyPaths = [])
  53. {
  54. $this->propertyPaths = \array_merge(
  55. $this->propertyPaths,
  56. ['file' => $filePropertyPath, 'name' => $fileNamePropertyPath],
  57. $propertyPaths
  58. );
  59. }
  60. /**
  61. * Gets the file property value for the given object.
  62. *
  63. * @param object $obj The object
  64. *
  65. * @return \Symfony\Component\HttpFoundation\File\UploadedFile|\Vich\UploaderBundle\FileAbstraction\ReplacingFile|null The file
  66. *
  67. * @throws \InvalidArgumentException
  68. */
  69. public function getFile($obj): ?File
  70. {
  71. return $this->readProperty($obj, 'file');
  72. }
  73. /**
  74. * Modifies the file property value for the given object.
  75. *
  76. * @param object $obj The object
  77. * @param File $file The new file
  78. *
  79. * @throws \InvalidArgumentException
  80. * @throws \TypeError
  81. */
  82. public function setFile($obj, File $file): void
  83. {
  84. $this->writeProperty($obj, 'file', $file);
  85. }
  86. /**
  87. * Gets the fileName property of the given object.
  88. *
  89. * @param object $obj The object
  90. *
  91. * @return string The filename
  92. *
  93. * @throws \InvalidArgumentException
  94. */
  95. public function getFileName($obj): ?string
  96. {
  97. return $this->readProperty($obj, 'name');
  98. }
  99. /**
  100. * Modifies the fileName property of the given object.
  101. *
  102. * @param object $obj The object
  103. *
  104. * @throws \InvalidArgumentException
  105. * @throws \TypeError
  106. */
  107. public function setFileName($obj, string $value): void
  108. {
  109. $this->writeProperty($obj, 'name', $value);
  110. }
  111. /**
  112. * Removes value for each file-related property of the given object.
  113. *
  114. * @param object $obj The object
  115. *
  116. * @throws \InvalidArgumentException
  117. * @throws \TypeError
  118. */
  119. public function erase($obj): void
  120. {
  121. foreach (['name', 'size', 'mimeType', 'originalName', 'dimensions'] as $property) {
  122. $this->writeProperty($obj, $property, null);
  123. }
  124. }
  125. /**
  126. * Reads property of the given object.
  127. *
  128. * @internal
  129. *
  130. * @param object $obj The object from which read
  131. * @param string $property The property to read
  132. *
  133. * @return mixed
  134. *
  135. * @throws \InvalidArgumentException
  136. */
  137. public function readProperty($obj, $property)
  138. {
  139. if (!\array_key_exists($property, $this->propertyPaths)) {
  140. throw new \InvalidArgumentException(\sprintf('Unknown property %s', $property));
  141. }
  142. if (!$this->propertyPaths[$property]) {
  143. // not configured
  144. return null;
  145. }
  146. $propertyPath = $this->fixPropertyPath($obj, $this->propertyPaths[$property]);
  147. return $this->getAccessor()->getValue($obj, $propertyPath);
  148. }
  149. /**
  150. * Modifies property of the given object.
  151. *
  152. * @internal
  153. *
  154. * @param object $obj The object to which write
  155. * @param string $property The property to write
  156. * @param mixed $value The value which should be written
  157. *
  158. * @throws \InvalidArgumentException
  159. * @throws \TypeError
  160. */
  161. public function writeProperty($obj, string $property, $value): void
  162. {
  163. if (!\array_key_exists($property, $this->propertyPaths)) {
  164. throw new \InvalidArgumentException(\sprintf('Unknown property %s', $property));
  165. }
  166. if (!$this->propertyPaths[$property]) {
  167. // not configured
  168. return;
  169. }
  170. $propertyPath = $this->fixPropertyPath($obj, $this->propertyPaths[$property]);
  171. $this->getAccessor()->setValue($obj, $propertyPath, $value);
  172. }
  173. /**
  174. * Gets the configured file property name.
  175. *
  176. * @return string The name
  177. */
  178. public function getFilePropertyName(): string
  179. {
  180. return $this->propertyPaths['file'];
  181. }
  182. /**
  183. * Gets the configured filename property name.
  184. *
  185. * @return string The name
  186. */
  187. public function getFileNamePropertyName(): string
  188. {
  189. return $this->propertyPaths['name'];
  190. }
  191. /**
  192. * Gets the configured namer.
  193. */
  194. public function getNamer(): ?NamerInterface
  195. {
  196. return $this->namer;
  197. }
  198. /**
  199. * Sets the namer.
  200. */
  201. public function setNamer(NamerInterface $namer): void
  202. {
  203. $this->namer = $namer;
  204. }
  205. /**
  206. * Determines if the mapping has a custom namer configured.
  207. */
  208. public function hasNamer(): bool
  209. {
  210. return null !== $this->namer;
  211. }
  212. /**
  213. * Gets the configured directory namer.
  214. */
  215. public function getDirectoryNamer(): ?DirectoryNamerInterface
  216. {
  217. return $this->directoryNamer;
  218. }
  219. /**
  220. * Sets the directory namer.
  221. */
  222. public function setDirectoryNamer(DirectoryNamerInterface $directoryNamer): void
  223. {
  224. $this->directoryNamer = $directoryNamer;
  225. }
  226. /**
  227. * Determines if the mapping has a custom directory namer configured.
  228. */
  229. public function hasDirectoryNamer(): bool
  230. {
  231. return null !== $this->directoryNamer;
  232. }
  233. /**
  234. * Sets the configured configuration mapping.
  235. *
  236. * @param array $mapping The mapping;
  237. */
  238. public function setMapping(array $mapping): void
  239. {
  240. $this->mapping = $mapping;
  241. }
  242. /**
  243. * Gets the configured configuration mapping name.
  244. */
  245. public function getMappingName(): string
  246. {
  247. return $this->mappingName;
  248. }
  249. /**
  250. * Sets the configured configuration mapping name.
  251. *
  252. * @param string $mappingName
  253. */
  254. public function setMappingName($mappingName): void
  255. {
  256. $this->mappingName = $mappingName;
  257. }
  258. /**
  259. * Gets the upload name for a given file (uses The file namers).
  260. *
  261. * @param object $obj
  262. *
  263. * @return string The upload name
  264. */
  265. public function getUploadName($obj): string
  266. {
  267. if (!$this->hasNamer()) {
  268. $msg = 'Not using a namer is deprecated and will be removed in version 2.';
  269. @\trigger_error($msg, \E_USER_DEPRECATED);
  270. return $this->getFile($obj)->getClientOriginalName();
  271. }
  272. return $this->getNamer()->name($obj, $this);
  273. }
  274. /**
  275. * Gets the upload directory for a given file (uses the directory namers).
  276. *
  277. * @param object $obj
  278. *
  279. * @return string|null The upload directory
  280. */
  281. public function getUploadDir($obj): ?string
  282. {
  283. if (!$this->hasDirectoryNamer()) {
  284. return '';
  285. }
  286. $dir = $this->getDirectoryNamer()->directoryName($obj, $this);
  287. // strip the trailing directory separator if needed
  288. $dir = $dir ? \rtrim($dir, '/\\') : $dir;
  289. return $dir;
  290. }
  291. /**
  292. * Gets the base upload directory.
  293. *
  294. * @return string The configured upload directory
  295. */
  296. public function getUploadDestination(): string
  297. {
  298. return $this->mapping['upload_destination'];
  299. }
  300. /**
  301. * Get uri prefix.
  302. */
  303. public function getUriPrefix(): string
  304. {
  305. return $this->mapping['uri_prefix'];
  306. }
  307. /**
  308. * Fixes a given propertyPath to make it usable both with arrays and
  309. * objects.
  310. * Ie: if the given object is in fact an array, the property path must
  311. * look like [myPath].
  312. *
  313. * @param object|array $object The object to inspect
  314. * @param string $propertyPath The property path to fix
  315. *
  316. * @return string The fixed property path
  317. */
  318. protected function fixPropertyPath($object, string $propertyPath): string
  319. {
  320. if (!\is_array($object)) {
  321. return $propertyPath;
  322. }
  323. return '[' === $propertyPath[0] ? $propertyPath : \sprintf('[%s]', $propertyPath);
  324. }
  325. protected function getAccessor(): PropertyAccessor
  326. {
  327. // TODO: reuse original property accessor from forms
  328. if (null !== $this->accessor) {
  329. return $this->accessor;
  330. }
  331. return $this->accessor = PropertyAccess::createPropertyAccessor();
  332. }
  333. }