diff --git a/lib/Alchemy/Phrasea/Core/Provider/SubdefServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SubdefServiceProvider.php index 8a16d4ca7c..1ef91b9bba 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SubdefServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SubdefServiceProvider.php @@ -22,13 +22,13 @@ class SubdefServiceProvider implements ServiceProviderInterface public function register(SilexApplication $app) { $app['subdef.generator'] = $app->share(function (Application $app) { - $generator = new SubdefGenerator($app, $app['media-alchemyst'], $app['filesystem'], $app['mediavorus'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']); + $generator = new SubdefGenerator($app, $app['media-alchemyst'], $app['phraseanet.filesystem'], $app['mediavorus'], isset($app['task-manager.logger']) ? $app['task-manager.logger'] : $app['monolog']); $generator->setDispatcher($app['dispatcher']); return $generator; }); $app['subdef.substituer'] = $app->share(function (Application $app) { - return new SubdefSubstituer($app, $app['filesystem'], $app['media-alchemyst'], $app['mediavorus'], $app['dispatcher']); + return new SubdefSubstituer($app, $app['phraseanet.filesystem'], $app['media-alchemyst'], $app['mediavorus'], $app['dispatcher']); }); } diff --git a/lib/Alchemy/Phrasea/Filesystem/FilesystemService.php b/lib/Alchemy/Phrasea/Filesystem/FilesystemService.php new file mode 100644 index 0000000000..b6b34894ce --- /dev/null +++ b/lib/Alchemy/Phrasea/Filesystem/FilesystemService.php @@ -0,0 +1,208 @@ +filesystem = $filesystem; + } + + /** + * @param string $repository_path + * @return string + */ + public function directorySpread($repository_path) + { + $repository_path = \p4string::addEndSlash($repository_path); + + $timestamp = strtotime(date('Y-m-d')); + $year = date('Y', $timestamp); + $month = date('m', $timestamp); + $day = date('d', $timestamp); + + $comp = $year . DIRECTORY_SEPARATOR . $month . DIRECTORY_SEPARATOR . $day . DIRECTORY_SEPARATOR; + + $n = 0; + do { + $pathout = sprintf('%s%s%05d', $repository_path, $comp, $n++); + } while (is_dir($pathout) && iterator_count(new \DirectoryIterator($pathout)) > 100); + + $this->filesystem->mkdir($pathout, 0750); + + return $pathout . DIRECTORY_SEPARATOR; + } + + public function exists($path) + { + return $this->filesystem->exists($path); + } + + public function generateSubdefPathname(\record_adapter $record, \databox_subdef $subdef, $oldVersion) + { + if ($oldVersion) { + $pathdest = \p4string::addEndSlash(pathinfo($oldVersion, PATHINFO_DIRNAME)); + } else { + $pathdest = $this->directorySpread($subdef->get_path()); + } + + return $pathdest . $this->generateSubdefFilename($record, $subdef); + } + + /** + * @param \record_adapter $record + * @param string|\SplFileInfo $source + * @return string + */ + public function generateDocumentFilename(\record_adapter $record, $source) + { + if (!$source instanceof \SplFileInfo) { + $source = new \SplFileInfo($source); + } + + return $record->getRecordId() . '_document' . strtolower($source->getExtension()); + } + + /** + * @param \record_adapter $record + * @param \databox_subdef $subdef + * @param string $marker + * @return string + */ + public function generateSubdefFilename(\record_adapter $record, \databox_subdef $subdef, $marker = '') + { + return $record->getRecordId() . '_' . $marker . $subdef->get_name() . '.' . $this->getExtensionFromSpec($subdef->getSpecs()); + } + + public function generateSubdefSubstitutionPathname(\record_adapter $record, \databox_subdef $subdef) + { + $pathdest = $this->directorySpread($subdef->get_path()); + + return $pathdest . $this->generateSubdefFilename($record, $subdef, '0_'); + } + + /** + * @param \databox $databox + * @return string + */ + public function generateDataboxDocumentBasePath(\databox $databox) + { + $baseprefs = $databox->get_sxml_structure(); + + return $this->directorySpread(\p4string::addEndSlash((string)($baseprefs->path))); + } + + /** + * Write Media source file with given filename + * + * @param \databox $databox + * @param string $source + * @param string $filename + */ + public function writeMediaSourceFile(\databox $databox, $source, $filename) + { + $realPath = $this->generateDataboxDocumentBasePath($databox) . $filename; + + $this->filesystem->copy($source, $realPath, true); + $this->filesystem->chmod($realPath, 0760); + } + + /** + * Copy file from source to target + * + * @param string $source + * @param string $target + */ + public function copy($source, $target) + { + $this->filesystem->copy($source, $target, true); + } + + public function chmod($files, $mode, $umask = 0000, $recursive = false) + { + $this->filesystem->chmod($files, $mode, $umask, $recursive); + } + + /** + * Get the extension from MediaAlchemyst specs + * + * @param SpecificationInterface $spec + * + * @return string + */ + private function getExtensionFromSpec(SpecificationInterface $spec) + { + switch ($spec->getType()) { + case SpecificationInterface::TYPE_IMAGE: + return 'jpg'; + case SpecificationInterface::TYPE_ANIMATION: + return 'gif'; + case SpecificationInterface::TYPE_AUDIO: + return $this->getExtensionFromAudioCodec($spec->getAudioCodec()); + case SpecificationInterface::TYPE_VIDEO: + return $this->getExtensionFromVideoCodec($spec->getVideoCodec()); + case SpecificationInterface::TYPE_SWF: + return 'swf'; + } + + return null; + } + + /** + * Get the extension from audiocodec + * + * @param string $audioCodec + * + * @return string + */ + private function getExtensionFromAudioCodec($audioCodec) + { + switch ($audioCodec) { + case 'flac': + return 'flac'; + case 'libvorbis': + return 'ogg'; + case 'libmp3lame': + return 'mp3'; + } + + return null; + } + + /** + * Get the extension from videocodec + * + * @param string $videoCodec + * + * @return string + */ + private function getExtensionFromVideoCodec($videoCodec) + { + switch ($videoCodec) { + case 'libtheora': + return 'ogv'; + case 'libvpx': + return 'webm'; + case 'libx264': + return 'mp4'; + } + + return null; + } +} diff --git a/lib/Alchemy/Phrasea/Filesystem/FilesystemServiceProvider.php b/lib/Alchemy/Phrasea/Filesystem/FilesystemServiceProvider.php index 72cb5788ea..707136bfc1 100644 --- a/lib/Alchemy/Phrasea/Filesystem/FilesystemServiceProvider.php +++ b/lib/Alchemy/Phrasea/Filesystem/FilesystemServiceProvider.php @@ -21,7 +21,7 @@ class FilesystemServiceProvider implements ServiceProviderInterface public function register(Application $app) { $app['filesystem'] = $app->share(function () { - new Filesystem(); + return new Filesystem(); }); $app['temporary-filesystem.temporary-fs'] = $app->share(function (Application $app) { @@ -30,6 +30,10 @@ class FilesystemServiceProvider implements ServiceProviderInterface $app['temporary-filesystem'] = $app->share(function (Application $app) { return new Manager($app['temporary-filesystem.temporary-fs'], $app['filesystem']); }); + + $app['phraseanet.filesystem'] = $app->share(function (Application $app) { + return new FilesystemService($app['filesystem']); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index 0ec5ce68a6..3168417c49 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -18,12 +18,11 @@ use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionsCreationEvent; use Alchemy\Phrasea\Core\Event\Record\SubDefinitionCreationFailedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Filesystem\FilesystemService; use MediaAlchemyst\Alchemyst; -use MediaAlchemyst\Specification\SpecificationInterface; use MediaVorus\MediaVorus; use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException; use Psr\Log\LoggerInterface; -use Symfony\Component\Filesystem\Filesystem; class SubdefGenerator { @@ -38,7 +37,7 @@ class SubdefGenerator private $logger; private $mediavorus; - public function __construct(Application $app, Alchemyst $alchemyst, Filesystem $filesystem, MediaVorus $mediavorus, LoggerInterface $logger) + public function __construct(Application $app, Alchemyst $alchemyst, FilesystemService $filesystem, MediaVorus $mediavorus, LoggerInterface $logger) { $this->app = $app; $this->alchemyst = $alchemyst; @@ -78,7 +77,7 @@ class SubdefGenerator $record->clearSubdefCache($subdefname); } - $pathdest = $this->generateSubdefPathname($record, $subdef, $pathdest); + $pathdest = $this->filesystem->generateSubdefPathname($record, $subdef, $pathdest); $this->dispatch( RecordEvents::SUB_DEFINITION_CREATION, @@ -141,82 +140,4 @@ class SubdefGenerator $this->logger->error(sprintf('Subdef generation failed for record %d with message %s', $record->getRecordId(), $e->getMessage())); } } - - private function generateSubdefPathname(\record_adapter $record, \databox_subdef $subdef, $oldVersion = null) - { - if ($oldVersion) { - $pathdest = \p4string::addEndSlash(pathinfo($oldVersion, PATHINFO_DIRNAME)); - } else { - $pathdest = \databox::dispatch($this->filesystem, $subdef->get_path()); - } - - return $pathdest . $record->getRecordId() . '_' . $subdef->get_name() . '.' . $this->getExtensionFromSpec($subdef->getSpecs()); - } - - /** - * Get the extension from MediaAlchemyst specs - * - * @param SpecificationInterface $spec - * - * @return string - */ - private function getExtensionFromSpec(SpecificationInterface $spec) - { - switch ($spec->getType()) { - case SpecificationInterface::TYPE_IMAGE: - return 'jpg'; - case SpecificationInterface::TYPE_ANIMATION: - return 'gif'; - case SpecificationInterface::TYPE_AUDIO: - return $this->getExtensionFromAudioCodec($spec->getAudioCodec()); - case SpecificationInterface::TYPE_VIDEO: - return $this->getExtensionFromVideoCodec($spec->getVideoCodec()); - case SpecificationInterface::TYPE_SWF: - return 'swf'; - } - - return null; - } - - /** - * Get the extension from audiocodec - * - * @param string $audioCodec - * - * @return string - */ - private function getExtensionFromAudioCodec($audioCodec) - { - switch ($audioCodec) { - case 'flac': - return 'flac'; - case 'libvorbis': - return 'ogg'; - case 'libmp3lame': - return 'mp3'; - } - - return null; - } - - /** - * Get the extension from videocodec - * - * @param string $videoCodec - * - * @return string - */ - private function getExtensionFromVideoCodec($videoCodec) - { - switch ($videoCodec) { - case 'libtheora': - return 'ogv'; - case 'libvpx': - return 'webm'; - case 'libx264': - return 'mp4'; - } - - return null; - } } diff --git a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php index e61eacf99b..e16045f8f1 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php +++ b/lib/Alchemy/Phrasea/Media/SubdefSubstituer.php @@ -13,12 +13,12 @@ namespace Alchemy\Phrasea\Media; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Core\Event\Record\MediaSubstitutedEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; +use Alchemy\Phrasea\Filesystem\FilesystemService; use MediaAlchemyst\Alchemyst; use MediaAlchemyst\Exception\ExceptionInterface as MediaAlchemystException; use MediaVorus\Media\MediaInterface; use MediaVorus\MediaVorus; use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Filesystem\Filesystem; class SubdefSubstituer { @@ -26,7 +26,7 @@ class SubdefSubstituer private $fs; private $mediavorus; - public function __construct(Application $app, Filesystem $fs, Alchemyst $alchemyst, MediaVorus $mediavorus, EventDispatcherInterface $dispatcher) + public function __construct(Application $app, FilesystemService $fs, Alchemyst $alchemyst, MediaVorus $mediavorus, EventDispatcherInterface $dispatcher) { $this->alchemyst = $alchemyst; $this->app = $app; @@ -56,18 +56,15 @@ class SubdefSubstituer public function substituteDocument(\record_adapter $record, MediaInterface $media) { - $baseprefs = $record->getDatabox()->get_sxml_structure(); - $pathhd = \databox::dispatch($this->fs, \p4string::addEndSlash((string) ($baseprefs->path))); + /** @var \SplFileInfo $file */ + $file = $media->getFile(); - $extension = strtolower($media->getFile()->getExtension()); - $filehd = $record->getRecordId() . "_document." . $extension; + $source = $file->getRealPath(); + $target = $this->fs->generateDocumentFilename($record, $file); - $subdefFile = $pathhd . $filehd; + $this->fs->writeMediaSourceFile($record->getDatabox(), $source, $target); - $this->fs->copy($media->getFile()->getRealPath(), $subdefFile, true); - $this->fs->chmod($subdefFile, 0760); - - $media = $this->mediavorus->guess($subdefFile); + $media = $this->mediavorus->guess($source); $this->createMediaSubdef($record, 'document', $media); @@ -98,9 +95,7 @@ class SubdefSubstituer $record->get_subdef($name)->remove_file(); $record->clearSubdefCache($name); } else { - $path = \databox::dispatch($this->fs, $databox_subdef->get_path()); - $this->fs->mkdir($path, 0750); - $path_file_dest = $path . $record->getRecordId() . '_0_' . $name . '.' . $media->getFile()->getExtension(); + $path_file_dest = $this->fs->generateSubdefSubstitutionPathname($record, $databox_subdef); } if($adapt) { diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 784c87ae4a..62371fec5f 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -158,23 +158,9 @@ class databox extends base implements ThumbnailedElement public static function dispatch(Filesystem $filesystem, $repository_path) { - $repository_path = p4string::addEndSlash($repository_path); + $filesystem = new \Alchemy\Phrasea\Filesystem\FilesystemService($filesystem); - $timestamp = strtotime(date('Y-m-d')); - $year = date('Y', $timestamp); - $month = date('m', $timestamp); - $day = date('d', $timestamp); - - $comp = $year . DIRECTORY_SEPARATOR . $month . DIRECTORY_SEPARATOR . $day . DIRECTORY_SEPARATOR; - - $n = 0; - do { - $pathout = sprintf('%s%s%05d', $repository_path, $comp, $n++); - } while (is_dir($pathout) && iterator_count(new DirectoryIterator($pathout)) > 100); - - $filesystem->mkdir($pathout, 0750); - - return $pathout . DIRECTORY_SEPARATOR; + return $filesystem->directorySpread($repository_path); } public static function get_available_dcfields() diff --git a/lib/classes/databox/subdefsStructure.php b/lib/classes/databox/subdefsStructure.php index 01d2506baa..58b0556451 100644 --- a/lib/classes/databox/subdefsStructure.php +++ b/lib/classes/databox/subdefsStructure.php @@ -1,5 +1,4 @@ databox->get_sxml_structure(); @@ -92,7 +87,7 @@ class databox_subdefsStructure implements IteratorAggregate, Countable ]; if (! $sx_struct) { - return $this; + return; } $subdefgroup = $sx_struct->subdefs[0]; @@ -132,8 +127,6 @@ class databox_subdefsStructure implements IteratorAggregate, Countable } } $this->AvSubdefs = $avSubdefs; - - return $this; } /** diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 32cb8d7757..840bb1711e 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -20,6 +20,7 @@ use Alchemy\Phrasea\Core\Event\Record\RecordEvent; use Alchemy\Phrasea\Core\Event\Record\RecordEvents; use Alchemy\Phrasea\Core\Event\Record\StatusChangedEvent; use Alchemy\Phrasea\Core\PhraseaTokens; +use Alchemy\Phrasea\Filesystem\FilesystemService; use Alchemy\Phrasea\Media\ArrayTechnicalDataSet; use Alchemy\Phrasea\Media\FloatTechnicalData; use Alchemy\Phrasea\Media\IntegerTechnicalData; @@ -36,7 +37,6 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Doctrine\ORM\EntityManager; use MediaVorus\MediaVorus; use Ramsey\Uuid\Uuid; -use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\File as SymfoFile; @@ -53,13 +53,11 @@ class record_adapter implements RecordInterface, cache_cacheableInterface /** * @param Application $app - * @return Filesystem + * @return FilesystemService */ private static function getFilesystem(Application $app) { - $filesystem = $app['filesystem']; - - return $filesystem; + return $app['phraseanet.filesystem']; } private $base_id; @@ -1161,7 +1159,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface } /** - * * @param File $file * @param Application $app * @@ -1211,10 +1208,10 @@ class record_adapter implements RecordInterface, cache_cacheableInterface $filesystem = self::getFilesystem($app); - $pathhd = databox::dispatch($filesystem, trim($databox->get_sxml_structure()->path)); - $newname = $record->getRecordId() . "_document." . pathinfo($file->getOriginalName(), PATHINFO_EXTENSION); + $pathhd = $filesystem->generateDataboxDocumentBasePath($databox); + $newname = $filesystem->generateDocumentFilename($record, $file->getFile()); - $filesystem->copy($file->getFile()->getRealPath(), $pathhd . $newname, true); + $filesystem->copy($file->getFile()->getRealPath(), $pathhd . $newname); $media = $app->getMediaFromUri($pathhd . $newname); media_subdef::create($app, $record, 'document', $media);