/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { $class = $this->getMetaReflectionClass($meta); // class annotations if ($annot = $this->reader->getClassAnnotation($class, self::UPLOADABLE)) { $config['uploadable'] = true; $config['allowOverwrite'] = $annot->allowOverwrite; $config['appendNumber'] = $annot->appendNumber; $config['path'] = $annot->path; $config['pathMethod'] = $annot->pathMethod; $config['fileMimeTypeField'] = false; $config['filePathField'] = false; $config['fileSizeField'] = false; $config['callback'] = $annot->callback; $config['filenameGenerator'] = $annot->filenameGenerator; $config['maxSize'] = (double) $annot->maxSize; $config['allowedTypes'] = $annot->allowedTypes; $config['disallowedTypes'] = $annot->disallowedTypes; foreach ($class->getProperties() as $prop) { if ($this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_MIME_TYPE)) { $config['fileMimeTypeField'] = $prop->getName(); } if ($this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_PATH)) { $config['filePathField'] = $prop->getName(); } if ($this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_SIZE)) { $config['fileSizeField'] = $prop->getName(); } } Validator::validateConfiguration($meta, $config); } /* // Code in case we need to identify entities which are not Uploadables, but have associations // with other Uploadable entities } else { // We need to check if this class has a relation with Uploadable entities $associations = $meta->getAssociationMappings(); foreach ($associations as $field => $association) { $refl = new \ReflectionClass($association['targetEntity']); if ($annot = $this->reader->getClassAnnotation($refl, self::UPLOADABLE)) { $config['hasUploadables'] = true; if (!isset($config['uploadables'])) { $config['uploadables'] = array(); } $config['uploadables'][] = array( 'class' => $association['targetEntity'], 'property' => $association['fieldName'] ); } } }*/ $this->validateFullMetadata($meta, $config); }
/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { /** * @var \SimpleXmlElement $xml */ $xml = $this->_getMapping($meta->name); $xmlDoctrine = $xml; $xml = $xml->children(self::GEDMO_NAMESPACE_URI); if ($xmlDoctrine->getName() == 'entity' || $xmlDoctrine->getName() == 'mapped-superclass') { if (isset($xml->uploadable)) { $xmlUploadable = $xml->uploadable; $config['uploadable'] = true; $config['allowOverwrite'] = $this->_isAttributeSet($xmlUploadable, 'allow-overwrite') ? (bool) $this->_getAttribute($xmlUploadable, 'allow-overwrite') : false; $config['appendNumber'] = $this->_isAttributeSet($xmlUploadable, 'append-number') ? (bool) $this->_getAttribute($xmlUploadable, 'append-number') : false; $config['path'] = $this->_isAttributeSet($xmlUploadable, 'path') ? $this->_getAttribute($xml->{'uploadable'}, 'path') : ''; $config['pathMethod'] = $this->_isAttributeSet($xmlUploadable, 'path-method') ? $this->_getAttribute($xml->{'uploadable'}, 'path-method') : ''; $config['callback'] = $this->_isAttributeSet($xmlUploadable, 'callback') ? $this->_getAttribute($xml->{'uploadable'}, 'callback') : ''; $config['fileMimeTypeField'] = false; $config['fileNameField'] = false; $config['filePathField'] = false; $config['fileSizeField'] = false; $config['filenameGenerator'] = $this->_isAttributeSet($xmlUploadable, 'filename-generator') ? $this->_getAttribute($xml->{'uploadable'}, 'filename-generator') : Validator::FILENAME_GENERATOR_NONE; $config['maxSize'] = $this->_isAttributeSet($xmlUploadable, 'max-size') ? (double) $this->_getAttribute($xml->{'uploadable'}, 'max-size') : (double) 0; $config['allowedTypes'] = $this->_isAttributeSet($xmlUploadable, 'allowed-types') ? $this->_getAttribute($xml->{'uploadable'}, 'allowed-types') : ''; $config['disallowedTypes'] = $this->_isAttributeSet($xmlUploadable, 'disallowed-types') ? $this->_getAttribute($xml->{'uploadable'}, 'disallowed-types') : ''; if (isset($xmlDoctrine->field)) { foreach ($xmlDoctrine->field as $mapping) { $mappingDoctrine = $mapping; $mapping = $mapping->children(self::GEDMO_NAMESPACE_URI); $field = $this->_getAttribute($mappingDoctrine, 'name'); if (isset($mapping->{'uploadable-file-mime-type'})) { $config['fileMimeTypeField'] = $field; } else { if (isset($mapping->{'uploadable-file-size'})) { $config['fileSizeField'] = $field; } else { if (isset($mapping->{'uploadable-file-name'})) { $config['fileNameField'] = $field; } else { if (isset($mapping->{'uploadable-file-path'})) { $config['filePathField'] = $field; } } } } } } Validator::validateConfiguration($meta, $config); } } }
public function setUp() { parent::setUp(); Validator::$enableMimeTypesConfigException = false; $reader = new AnnotationReader(); $annotationDriver = new AnnotationDriver($reader); $xmlDriver = new XmlDriver(__DIR__ . '/../Driver/Xml'); $chain = new DriverChain(); $chain->addDriver($xmlDriver, 'Mapping\\Fixture\\Xml'); $chain->addDriver($annotationDriver, 'Mapping\\Fixture'); $this->listener = new UploadableListener(); $this->evm = new EventManager(); $this->evm->addEventSubscriber($this->listener); $this->em = $this->getMockSqliteEntityManager(array('Mapping\\Fixture\\Xml\\Uploadable'), $chain); }
/** * {@inheritDoc} */ public function readExtendedMetadata($meta, array &$config) { $mapping = $this->_getMapping($meta->name); if (isset($mapping['gedmo'])) { $classMapping = $mapping['gedmo']; if (isset($classMapping['uploadable'])) { $uploadable = $classMapping['uploadable']; $config['uploadable'] = true; $config['allowOverwrite'] = isset($uploadable['allowOverwrite']) ? (bool) $uploadable['allowOverwrite'] : false; $config['appendNumber'] = isset($uploadable['appendNumber']) ? (bool) $uploadable['appendNumber'] : false; $config['path'] = isset($uploadable['path']) ? $uploadable['path'] : ''; $config['pathMethod'] = isset($uploadable['pathMethod']) ? $uploadable['pathMethod'] : ''; $config['callback'] = isset($uploadable['callback']) ? $uploadable['callback'] : ''; $config['fileMimeTypeField'] = false; $config['fileNameField'] = false; $config['filePathField'] = false; $config['fileSizeField'] = false; $config['filenameGenerator'] = isset($uploadable['filenameGenerator']) ? $uploadable['filenameGenerator'] : Validator::FILENAME_GENERATOR_NONE; $config['maxSize'] = isset($uploadable['maxSize']) ? (double) $uploadable['maxSize'] : (double) 0; $config['allowedTypes'] = isset($uploadable['allowedTypes']) ? $uploadable['allowedTypes'] : ''; $config['disallowedTypes'] = isset($uploadable['disallowedTypes']) ? $uploadable['disallowedTypes'] : ''; if (isset($mapping['fields'])) { foreach ($mapping['fields'] as $field => $info) { if (isset($info['gedmo']) && array_key_exists(0, $info['gedmo'])) { if ($info['gedmo'][0] === 'uploadableFileMimeType') { $config['fileMimeTypeField'] = $field; } else { if ($info['gedmo'][0] === 'uploadableFileSize') { $config['fileSizeField'] = $field; } else { if ($info['gedmo'][0] === 'uploadableFileName') { $config['fileNameField'] = $field; } else { if ($info['gedmo'][0] === 'uploadableFilePath') { $config['filePathField'] = $field; } } } } } } } Validator::validateConfiguration($meta, $config); } } }
public function boot() { if ($this->container->hasParameter('stof_doctrine_extensions.uploadable.validate_writable_directory')) { Validator::$validateWritableDirectory = $this->container->getParameter('stof_doctrine_extensions.uploadable.validate_writable_directory'); } }
/** * If it's a Uploadable object, verify if the file was uploaded. * If that's the case, process it. * * @param \Gedmo\Mapping\Event\AdapterInterface $ea * @param $object * @param $action * @throws \Gedmo\Exception\UploadableNoPathDefinedException * @throws \Gedmo\Exception\UploadableCouldntGuessMimeTypeException * @throws \Gedmo\Exception\UploadableMaxSizeException * @throws \Gedmo\Exception\UploadableInvalidMimeTypeException */ public function processFile(AdapterInterface $ea, $object, $action) { $oid = spl_object_hash($object); $om = $ea->getObjectManager(); $uow = $om->getUnitOfWork(); $meta = $om->getClassMetadata(get_class($object)); $config = $this->getConfiguration($om, $meta->name); if (!$config || !isset($config['uploadable']) || !$config['uploadable']) { // Nothing to do return; } $refl = $meta->getReflectionClass(); $fileInfo = $this->fileInfoObjects[$oid]['fileInfo']; $evm = $om->getEventManager(); if ($evm->hasListeners(Events::uploadablePreFileProcess)) { $evm->dispatchEvent(Events::uploadablePreFileProcess, new UploadablePreFileProcessEventArgs($this, $om, $config, $fileInfo, $object, $action)); } // Validations if ($config['maxSize'] > 0 && $fileInfo->getSize() > $config['maxSize']) { $msg = 'File "%s" exceeds the maximum allowed size of %d bytes. File size: %d bytes'; throw new UploadableMaxSizeException(sprintf($msg, $fileInfo->getName(), $config['maxSize'], $fileInfo->getSize())); } $mime = $this->mimeTypeGuesser->guess($fileInfo->getTmpName()); if (!$mime) { throw new UploadableCouldntGuessMimeTypeException(sprintf('Couldn\'t guess mime type for file "%s".', $fileInfo->getName())); } if ($config['allowedTypes'] || $config['disallowedTypes']) { $ok = $config['allowedTypes'] ? false : true; $mimes = $config['allowedTypes'] ? $config['allowedTypes'] : $config['disallowedTypes']; foreach ($mimes as $m) { if ($mime === $m) { $ok = $config['allowedTypes'] ? true : false; break; } } if (!$ok) { throw new UploadableInvalidMimeTypeException(sprintf('Invalid mime type "%s" for file "%s".', $mime, $fileInfo->getName())); } } $filePathField = $refl->getProperty($config['filePathField']); $filePathField->setAccessible(true); $path = $config['path']; if ($path === '') { if ($config['pathMethod'] !== '') { $pathMethod = $refl->getMethod($config['pathMethod']); $pathMethod->setAccessible(true); $path = $pathMethod->invoke($object); } else { if ($this->getDefaultPath() !== null) { $path = $this->getDefaultPath(); } else { $msg = 'You have to define the path to save files either in the listener, or in the class "%s"'; throw new UploadableNoPathDefinedException(sprintf($msg, $meta->name)); } } } Validator::validatePath($path); $path = substr($path, strlen($path) - 1) === '/' ? substr($path, 0, strlen($path) - 2) : $path; if ($config['fileMimeTypeField']) { $fileMimeTypeField = $refl->getProperty($config['fileMimeTypeField']); $fileMimeTypeField->setAccessible(true); } if ($config['fileSizeField']) { $fileSizeField = $refl->getProperty($config['fileSizeField']); $fileSizeField->setAccessible(true); } if ($action === self::ACTION_UPDATE) { // First we add the original file to the pendingFileRemovals array $this->pendingFileRemovals[] = $this->getFilePath($meta, $config, $object); } // We generate the filename based on configuration $generatorNamespace = 'Gedmo\\Uploadable\\FilenameGenerator'; switch ($config['filenameGenerator']) { case Validator::FILENAME_GENERATOR_ALPHANUMERIC: $generatorClass = $generatorNamespace . '\\FilenameGeneratorAlphanumeric'; break; case Validator::FILENAME_GENERATOR_SHA1: $generatorClass = $generatorNamespace . '\\FilenameGeneratorSha1'; break; case Validator::FILENAME_GENERATOR_NONE: $generatorClass = false; break; default: $generatorClass = $config['filenameGenerator']; } $info = $this->moveFile($fileInfo, $path, $generatorClass, $config['allowOverwrite'], $config['appendNumber']); // We override the mime type with the guessed one $info['fileMimeType'] = $mime; $filePathField->setValue($object, $info['filePath']); if ($config['callback'] !== '') { $callbackMethod = $refl->getMethod($config['callback']); $callbackMethod->setAccessible(true); $callbackMethod->invokeArgs($object, array($info)); } $changes = array($config['filePathField'] => array($filePathField->getValue($object), $info['filePath'])); if ($config['fileMimeTypeField']) { $changes[$config['fileMimeTypeField']] = array($fileMimeTypeField->getValue($object), $info['fileMimeType']); $this->updateField($object, $uow, $ea, $meta, $config['fileMimeTypeField'], $info['fileMimeType']); } if ($config['fileSizeField']) { $changes[$config['fileSizeField']] = array($fileSizeField->getValue($object), $info['fileSize']); $this->updateField($object, $uow, $ea, $meta, $config['fileSizeField'], $info['fileSize']); } $this->updateField($object, $uow, $ea, $meta, $config['filePathField'], $info['filePath']); $ea->recomputeSingleObjectChangeSet($uow, $meta, $object); if ($evm->hasListeners(Events::uploadablePostFileProcess)) { $evm->dispatchEvent(Events::uploadablePostFileProcess, new UploadablePostFileProcessEventArgs($this, $om, $config, $fileInfo, $object, $action)); } unset($this->fileInfoObjects[$oid]); }
/** * @param ClassMetadata $meta * @param array $config * @param object $object Entity * * @return string * * @throws UploadableNoPathDefinedException */ protected function getPath(ClassMetadata $meta, array $config, $object) { $path = $config['path']; if ($path === '') { $defaultPath = $this->getDefaultPath(); if ($config['pathMethod'] !== '') { $pathMethod = $meta->getReflectionClass()->getMethod($config['pathMethod']); $pathMethod->setAccessible(true); $path = $pathMethod->invoke($object, $defaultPath); } elseif ($defaultPath !== null) { $path = $defaultPath; } else { $msg = 'You have to define the path to save files either in the listener, or in the class "%s"'; throw new UploadableNoPathDefinedException(sprintf($msg, $meta->name)); } } Validator::validatePath($path); $path = rtrim($path, '\\/'); return $path; }
protected function readUploadableMetadata(\ReflectionClass $class, Uploadable $annot, $meta) { $config = array(); $config['uploadable'] = true; $config['allowOverwrite'] = $annot->allowOverwrite; $config['appendNumber'] = $annot->appendNumber; $config['path'] = $annot->path; $config['pathMethod'] = $annot->pathMethod; $config['fileMimeTypeField'] = false; $config['fileNameField'] = false; $config['filePathField'] = false; $config['fileSizeField'] = false; $config['callback'] = $annot->callback; $config['filenameGenerator'] = $annot->filenameGenerator; $config['maxSize'] = (double) $annot->maxSize; $config['allowedTypes'] = $annot->allowedTypes; $config['disallowedTypes'] = $annot->disallowedTypes; foreach ($class->getProperties() as $prop) { if ($propAnnot = $this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_MIME_TYPE)) { if ($propAnnot->identifier == $annot->identifier) { $config['fileMimeTypeField'] = $prop->getName(); } } if ($propAnnot = $this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_NAME)) { if ($propAnnot->identifier == $annot->identifier) { $config['fileNameField'] = $prop->getName(); } } if ($propAnnot = $this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_PATH)) { if ($propAnnot->identifier == $annot->identifier) { $config['filePathField'] = $prop->getName(); } } if ($propAnnot = $this->reader->getPropertyAnnotation($prop, self::UPLOADABLE_FILE_SIZE)) { if ($propAnnot->identifier == $annot->identifier) { $config['fileSizeField'] = $prop->getName(); } } } Validator::validateConfiguration($meta, $config); return $config; }
/** * @expectedException Gedmo\Exception\InvalidMappingException */ public function test_validateConfiguration_ifAllowedTypesAndDisallowedTypesAreSetThenThrowException() { $this->meta->expects($this->once())->method('getReflectionClass')->will($this->returnValue(new \ReflectionClass(new FakeEntity()))); Validator::$enableMimeTypesConfigException = true; $config = array('fileMimeTypeField' => 'someField', 'filePathField' => 'someField', 'fileSizeField' => '', 'pathMethod' => '', 'callback' => '', 'maxSize' => 0, 'allowedTypes' => 'text/plain', 'disallowedTypes' => 'text/css'); Validator::validateConfiguration($this->meta, $config); }