vendor/vich/uploader-bundle/src/Mapping/PropertyMappingFactory.php line 104

Open in your IDE?
  1. <?php
  2. namespace Vich\UploaderBundle\Mapping;
  3. use Doctrine\Persistence\Proxy;
  4. use Symfony\Component\DependencyInjection\ContainerInterface;
  5. use Vich\UploaderBundle\Exception\MappingNotFoundException;
  6. use Vich\UploaderBundle\Exception\NotUploadableException;
  7. use Vich\UploaderBundle\Metadata\MetadataReader;
  8. use Vich\UploaderBundle\Naming\ConfigurableInterface;
  9. use Vich\UploaderBundle\Util\ClassUtils;
  10. /**
  11.  * PropertyMappingFactory.
  12.  *
  13.  * @author Dustin Dobervich <ddobervich@gmail.com>
  14.  * @final
  15.  *
  16.  * @internal
  17.  */
  18. class PropertyMappingFactory
  19. {
  20.     /**
  21.      * @var ContainerInterface
  22.      */
  23.     protected $container;
  24.     /**
  25.      * @var MetadataReader
  26.      */
  27.     protected $metadata;
  28.     /**
  29.      * @var array
  30.      */
  31.     protected $mappings;
  32.     /**
  33.      * @var string
  34.      */
  35.     protected $defaultFilenameAttributeSuffix;
  36.     public function __construct(ContainerInterface $containerMetadataReader $metadata, array $mappings, ?string $defaultFilenameAttributeSuffix '_name')
  37.     {
  38.         $this->container $container;
  39.         $this->metadata $metadata;
  40.         $this->mappings $mappings;
  41.         $this->defaultFilenameAttributeSuffix $defaultFilenameAttributeSuffix;
  42.     }
  43.     /**
  44.      * Creates an array of PropetyMapping objects which contain the
  45.      * configuration for the uploadable fields in the specified
  46.      * object.
  47.      *
  48.      * @param object      $obj         The object
  49.      * @param string|null $className   The object's class. Mandatory if $obj can't be used to determine it
  50.      * @param string|null $mappingName The mapping name
  51.      *
  52.      * @return array|PropertyMapping[] An array up PropertyMapping objects
  53.      *
  54.      * @throws \RuntimeException
  55.      * @throws MappingNotFoundException
  56.      * @throws NotUploadableException
  57.      */
  58.     public function fromObject($obj, ?string $className null, ?string $mappingName null): array
  59.     {
  60.         if ($obj instanceof Proxy) {
  61.             $obj->__load();
  62.         }
  63.         $class $this->getClassName($obj$className);
  64.         $this->checkUploadable($class);
  65.         $mappings = [];
  66.         foreach ($this->metadata->getUploadableFields($class) as $field => $mappingData) {
  67.             if (null !== $mappingName && $mappingName !== $mappingData['mapping']) {
  68.                 continue;
  69.             }
  70.             $mappings[] = $this->createMapping($obj$field$mappingData);
  71.         }
  72.         return $mappings;
  73.     }
  74.     /**
  75.      * Creates a property mapping object which contains the
  76.      * configuration for the specified uploadable field.
  77.      *
  78.      * @param object|array $obj       The object
  79.      * @param string       $field     The field
  80.      * @param string|null  $className The object's class. Mandatory if $obj can't be used to determine it
  81.      *
  82.      * @return PropertyMapping|null The property mapping
  83.      *
  84.      * @throws \RuntimeException
  85.      * @throws MappingNotFoundException
  86.      * @throws NotUploadableException
  87.      */
  88.     public function fromField($objstring $field, ?string $className null): ?PropertyMapping
  89.     {
  90.         if ($obj instanceof Proxy) {
  91.             $obj->__load();
  92.         }
  93.         $class $this->getClassName($obj$className);
  94.         $this->checkUploadable($class);
  95.         $mappingData $this->metadata->getUploadableField($class$field);
  96.         if (null === $mappingData) {
  97.             return null;
  98.         }
  99.         return $this->createMapping($obj$field$mappingData);
  100.     }
  101.     public function fromFirstField(object $obj, ?string $className null): ?PropertyMapping
  102.     {
  103.         if ($obj instanceof Proxy) {
  104.             $obj->__load();
  105.         }
  106.         $class $this->getClassName($obj$className);
  107.         $this->checkUploadable($class);
  108.         $mappingData $this->metadata->getUploadableFields($class);
  109.         if (=== \count($mappingData)) {
  110.             return null;
  111.         }
  112.         return $this->createMapping($obj, \key($mappingData), \reset($mappingData));
  113.     }
  114.     /**
  115.      * Checks to see if the class is uploadable.
  116.      *
  117.      * @param string $class The class name (FQCN)
  118.      *
  119.      * @throws NotUploadableException
  120.      */
  121.     protected function checkUploadable(string $class): void
  122.     {
  123.         if (!$this->metadata->isUploadable($class)) {
  124.             throw new NotUploadableException(\sprintf('The class "%s" is not uploadable. If you use attributes to configure VichUploaderBundle, you probably just forgot to add `#[Vich\Uploadable]` on top of your entity. If you don\'t use attributes, check that the configuration files are in the right place. In both cases, clearing the cache can also solve the issue.'$class));
  125.         }
  126.     }
  127.     /**
  128.      * Creates the property mapping from the read annotation and configured mapping.
  129.      *
  130.      * @param object $obj         The object
  131.      * @param string $fieldName   The field name
  132.      * @param array  $mappingData The mapping data
  133.      *
  134.      * @return PropertyMapping The property mapping
  135.      *
  136.      * @throws \LogicException
  137.      * @throws MappingNotFoundException
  138.      */
  139.     protected function createMapping($objstring $fieldName, array $mappingData): PropertyMapping
  140.     {
  141.         if (!\array_key_exists($mappingData['mapping'], $this->mappings)) {
  142.             throw MappingNotFoundException::createNotFoundForClassAndField($mappingData['mapping'], $this->getClassName($obj), $fieldName);
  143.         }
  144.         $config $this->mappings[$mappingData['mapping']];
  145.         $fileProperty $mappingData['propertyName'] ?? $fieldName;
  146.         $fileNameProperty = empty($mappingData['fileNameProperty']) ? $fileProperty.$this->defaultFilenameAttributeSuffix $mappingData['fileNameProperty'];
  147.         $mapping = new PropertyMapping($fileProperty$fileNameProperty$mappingData);
  148.         $mapping->setMappingName($mappingData['mapping']);
  149.         $mapping->setMapping($config);
  150.         if (!empty($config['namer']) && null !== $config['namer']['service']) {
  151.             $namerConfig $config['namer'];
  152.             $namer $this->container->get($namerConfig['service']);
  153.             if (!empty($namerConfig['options'])) {
  154.                 if (!$namer instanceof ConfigurableInterface) {
  155.                     throw new \LogicException(\sprintf('Namer %s can not receive options as it does not implement ConfigurableInterface.'$namerConfig['service']));
  156.                 }
  157.                 $namer->configure($namerConfig['options']);
  158.             }
  159.             $mapping->setNamer($namer);
  160.         }
  161.         if (!empty($config['directory_namer']) && null !== $config['directory_namer']['service']) {
  162.             $namerConfig $config['directory_namer'];
  163.             $namer $this->container->get($namerConfig['service']);
  164.             if (!empty($namerConfig['options'])) {
  165.                 if (!$namer instanceof ConfigurableInterface) {
  166.                     throw new \LogicException(\sprintf('Namer %s can not receive options as it does not implement ConfigurableInterface.'$namerConfig['service']));
  167.                 }
  168.                 $namer->configure($namerConfig['options']);
  169.             }
  170.             $mapping->setDirectoryNamer($namer);
  171.         }
  172.         return $mapping;
  173.     }
  174.     /**
  175.      * Returns the className of the given object.
  176.      *
  177.      * @param object|mixed $object    The object to inspect
  178.      * @param string|null  $className User specified className
  179.      *
  180.      * @throws \RuntimeException
  181.      */
  182.     protected function getClassName($object, ?string $className null): string
  183.     {
  184.         if (null !== $className) {
  185.             return $className;
  186.         }
  187.         if (\is_object($object)) {
  188.             return ClassUtils::getClass($object);
  189.         }
  190.         throw new \RuntimeException('Impossible to determine the class name. Either specify it explicitly or give an object');
  191.     }
  192. }