From 2b097e9be7ec91afd7ead121a0aa020bb1118820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Wed, 24 Feb 2016 13:52:33 +0100 Subject: [PATCH 1/6] Extract SubdefGroup class --- lib/Alchemy/Phrasea/Databox/SubdefGroup.php | 115 ++++++++++++++++++ .../Phrasea/Media/MediaTypeFactory.php | 37 ++++++ lib/classes/databox/subdefsStructure.php | 113 +++++++---------- 3 files changed, 199 insertions(+), 66 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Databox/SubdefGroup.php create mode 100644 lib/Alchemy/Phrasea/Media/MediaTypeFactory.php diff --git a/lib/Alchemy/Phrasea/Databox/SubdefGroup.php b/lib/Alchemy/Phrasea/Databox/SubdefGroup.php new file mode 100644 index 0000000000..0cc82d7f51 --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/SubdefGroup.php @@ -0,0 +1,115 @@ +name = $name; + $this->type = $type; + $this->isDocumentOrderable = $isDocumentOrderable; + } + + /** + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * @return Type + */ + public function getType() + { + return $this->type; + } + + /** + * @return bool + */ + public function isDocumentOrderable() + { + return $this->isDocumentOrderable; + } + + public function addSubdef(\databox_subdef $subdef) + { + $this->subdefs[$subdef->get_name()] = $subdef; + } + + /** + * @param string|\databox_subdef $subdef + * @return bool + */ + public function hasSubdef($subdef) + { + $subdefName = $subdef instanceof \databox_subdef ? $subdef->get_name() : $subdef; + + return isset($this->subdefs[$subdefName]); + } + + /** + * @param string $subdefName + * @return \databox_subdef + */ + public function getSubdef($subdefName) + { + if (!isset($this->subdefs[$subdefName])) { + throw new \RuntimeException('Requested subdef was not found'); + } + + return $this->subdefs[$subdefName]; + } + + /** + * @param string|\databox_subdef $subdef + */ + public function removeSubdef($subdef) + { + $subdefName = $subdef instanceof \databox_subdef ? $subdef->get_name() : $subdef; + + unset($this->subdefs[$subdefName]); + } + + public function getIterator() + { + return new \ArrayIterator($this->subdefs); + } + + public function count() + { + return count($this->subdefs); + } +} diff --git a/lib/Alchemy/Phrasea/Media/MediaTypeFactory.php b/lib/Alchemy/Phrasea/Media/MediaTypeFactory.php new file mode 100644 index 0000000000..33a351ce5f --- /dev/null +++ b/lib/Alchemy/Phrasea/Media/MediaTypeFactory.php @@ -0,0 +1,37 @@ +AvSubdefs); + return new ArrayIterator($this->subdefGroups); } public function count() { $n = 0; - foreach ($this->AvSubdefs as $subdefs) { + + foreach ($this->subdefGroups as $subdefs) { $n += count($subdefs); } return $n; } - /** - * @param databox $databox - */ public function __construct(databox $databox, TranslatorInterface $translator) { $this->databox = $databox; @@ -59,16 +59,14 @@ class databox_subdefsStructure implements IteratorAggregate, Countable /** * @param string $searchGroup - * @return databox_subdef[] + * @return SubdefGroup|databox_subdef[] */ public function getSubdefGroup($searchGroup) { $searchGroup = strtolower($searchGroup); - foreach ($this->AvSubdefs as $groupname => $subdefgroup) { - if ($searchGroup == $groupname) { - return $subdefgroup; - } + if (isset($this->subdefGroups[$searchGroup])) { + return $this->subdefGroups[$searchGroup]; } return null; @@ -78,55 +76,36 @@ class databox_subdefsStructure implements IteratorAggregate, Countable { $sx_struct = $this->databox->get_sxml_structure(); - $avSubdefs = [ - 'image' => [], - 'video' => [], - 'audio' => [], - 'document' => [], - 'flash' => [] - ]; - if (! $sx_struct) { return; } $subdefgroup = $sx_struct->subdefs[0]; + $mediaTypeFactory = new MediaTypeFactory(); + foreach ($subdefgroup as $k => $subdefs) { $subdefgroup_name = strtolower($subdefs->attributes()->name); + $isDocumentOrderable = isset($subdefs->attributes()->document_orderable) + ? p4field::isyes($subdefs->attributes()->document_orderable) : true; - if ( ! isset($avSubdefs[$subdefgroup_name])) { - $avSubdefs[$subdefgroup_name] = []; - } - - foreach ($subdefs as $sd) { - $subdef_name = strtolower($sd->attributes()->name); - - $type = null; - switch ($subdefgroup_name) { - case 'audio': - $type = new \Alchemy\Phrasea\Media\Type\Audio(); - break; - case 'image': - $type = new \Alchemy\Phrasea\Media\Type\Image(); - break; - case 'video': - $type = new \Alchemy\Phrasea\Media\Type\Video(); - break; - case 'document': - $type = new \Alchemy\Phrasea\Media\Type\Document(); - break; - case 'flash': - $type = new \Alchemy\Phrasea\Media\Type\Flash(); - break; - default: - continue; + if (! isset($this->subdefGroups[$subdefgroup_name])) { + try { + $type = $mediaTypeFactory->createMediaType($subdefgroup_name); + } catch (RuntimeException $exception) { + // Skip undefined media type group + continue; } - $avSubdefs[$subdefgroup_name][$subdef_name] = new databox_subdef($type, $sd, $this->translator); + $this->subdefGroups[$subdefgroup_name] = new SubdefGroup($subdefgroup_name, $type, $isDocumentOrderable); + } + + $group = $this->getSubdefGroup($subdefgroup_name); + + foreach ($subdefs as $sd) { + $group->addSubdef(new databox_subdef($group->getType(), $sd, $this->translator)); } } - $this->AvSubdefs = $avSubdefs; } /** @@ -137,11 +116,10 @@ class databox_subdefsStructure implements IteratorAggregate, Countable */ public function hasSubdef($subdef_type, $subdef_name) { - $type = strtolower($subdef_type); - $name = strtolower($subdef_name); + $group = $this->getSubdefGroup(strtolower($subdef_type)); - if (isset($this->AvSubdefs[$type][$name])) { - return true; + if ($group) { + return $group->hasSubdef(strtolower($subdef_name)); } return false; @@ -159,22 +137,26 @@ class databox_subdefsStructure implements IteratorAggregate, Countable $type = strtolower($subdef_type); $name = strtolower($subdef_name); - if (isset($this->AvSubdefs[$type]) && isset($this->AvSubdefs[$type][$name])) { - return $this->AvSubdefs[$type][$name]; + $group = $this->getSubdefGroup(strtolower($subdef_type)); + + if (!$group) { + throw new Exception_Databox_SubdefNotFound(sprintf('Databox subdef name `%s` of type `%s` not found', $name, $type)); } - throw new Exception_Databox_SubdefNotFound(sprintf('Databox subdef name `%s` of type `%s` not found', $name, $type)); + try { + return $group->getSubdef($name); + } catch (RuntimeException $exception) { + throw new Exception_Databox_SubdefNotFound(sprintf('Databox subdef name `%s` of type `%s` not found', $name, $type), $exception); + } } /** - * - * @param string $group - * @param string $name - * @return databox_subdefsStructure + * @param string $group + * @param string $name + * @return self */ public function delete_subdef($group, $name) { - $dom_struct = $this->databox->get_dom_structure(); $dom_xp = $this->databox->get_xpath_structure(); $nodes = $dom_xp->query( @@ -189,8 +171,8 @@ class databox_subdefsStructure implements IteratorAggregate, Countable $parent->removeChild($node); } - if (isset($AvSubdefs[$group]) && isset($AvSubdefs[$group][$name])) { - unset($AvSubdefs[$group][$name]); + if ($this->hasSubdef($group, $name)) { + $this->getSubdefGroup($group)->removeSubdef($name); } $this->databox->saveStructure($dom_struct); @@ -199,10 +181,9 @@ class databox_subdefsStructure implements IteratorAggregate, Countable } /** - * - * @param string $groupname - * @param string $name - * @param string $class + * @param string $groupname + * @param string $name + * @param string $class * @return databox_subdefsStructure */ public function add_subdef($groupname, $name, $class) From ca6c3f99207a0d02b4e35f1b19f13d09a530c56a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Wed, 24 Feb 2016 13:54:35 +0100 Subject: [PATCH 2/6] Changes on SubdefGroup reflected in using clients --- lib/Alchemy/Phrasea/Controller/DatafileController.php | 10 ++++------ .../Phrasea/Controller/Prod/ToolsController.php | 2 +- lib/Alchemy/Phrasea/Media/SubdefGenerator.php | 1 + 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/DatafileController.php b/lib/Alchemy/Phrasea/Controller/DatafileController.php index c6449111ae..15fb91a3ae 100644 --- a/lib/Alchemy/Phrasea/Controller/DatafileController.php +++ b/lib/Alchemy/Phrasea/Controller/DatafileController.php @@ -44,11 +44,9 @@ class DatafileController extends AbstractDelivery if ($subdef != 'thumbnail') { $all_access = false; - $subdefStruct = $databox->get_subdef_structure(); - - if ($subdefStruct->getSubdefGroup($record->get_type())) { - foreach ($subdefStruct->getSubdefGroup($record->get_type()) as $subdefObj) { - /** @var \databox_subdef $subdefObj */ + $subdefGroup = $databox->get_subdef_structure()->getSubdefGroup($record->getType()); + if ($subdefGroup) { + foreach ($subdefGroup as $subdefObj) { if ($subdefObj->get_name() == $subdef) { if ($subdefObj->get_class() == 'thumbnail') { $all_access = true; @@ -75,7 +73,7 @@ class DatafileController extends AbstractDelivery try { $subdef_class = $databox ->get_subdef_structure() - ->get_subdef($record->get_type(), $subdef) + ->get_subdef($record->getType(), $subdef) ->get_class(); } catch (\Exception_Databox_SubdefNotFound $e) { diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php index da497eb9ec..cd22dc8740 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php @@ -73,7 +73,7 @@ class ToolsController extends Controller continue; } - $label = $databoxSubdefs[$subdefName]->get_label($this->app['locale']); + $label = $databoxSubdefs->getSubdef($subdefName)->get_label($this->app['locale']); } $recordAccessibleSubdefs[] = array( 'name' => $subdef->get_name(), diff --git a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php index 3168417c49..47ce36fe97 100644 --- a/lib/Alchemy/Phrasea/Media/SubdefGenerator.php +++ b/lib/Alchemy/Phrasea/Media/SubdefGenerator.php @@ -50,6 +50,7 @@ class SubdefGenerator { if (null === $subdefs = $record->getDatabox()->get_subdef_structure()->getSubdefGroup($record->getType())) { $this->logger->info(sprintf('Nothing to do for %s', $record->getType())); + $subdefs = []; } $this->dispatch( From c053ef5045e117670576b691a8fef8eb6bb35a89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Fri, 22 Apr 2016 16:14:10 +0200 Subject: [PATCH 3/6] Fixup invalid method name causing tooltip error --- .../Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php index 432f9e0753..307350fc72 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/RecordEditSubscriber.php @@ -26,7 +26,7 @@ class RecordEditSubscriber implements EventSubscriberInterface return array( PhraseaEvents::RECORD_EDIT => 'onEdit', PhraseaEvents::RECORD_UPLOAD => 'onEdit', - RecordEvents::ROTATE => 'onRotate', + RecordEvents::ROTATE => 'onRecordChange', ); } From f84f625a4e750998f5d6e0234ba69ad76948e75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Fri, 22 Apr 2016 16:15:37 +0200 Subject: [PATCH 4/6] All media_subdef updates go to the repository --- .../Databox/Subdef/MediaSubdefRepository.php | 40 ++++++-- lib/classes/media/subdef.php | 91 ++++--------------- 2 files changed, 52 insertions(+), 79 deletions(-) diff --git a/lib/Alchemy/Phrasea/Databox/Subdef/MediaSubdefRepository.php b/lib/Alchemy/Phrasea/Databox/Subdef/MediaSubdefRepository.php index aba28b6fd1..3d581ef596 100644 --- a/lib/Alchemy/Phrasea/Databox/Subdef/MediaSubdefRepository.php +++ b/lib/Alchemy/Phrasea/Databox/Subdef/MediaSubdefRepository.php @@ -81,18 +81,26 @@ class MediaSubdefRepository */ public function save($subdefs) { - if (!is_array($subdefs) || !$subdefs instanceof \Traversable) { - $subdefs = [$subdefs]; - } elseif ($subdefs instanceof \Traversable) { - $subdefs = iterator_to_array($subdefs); - } - Assertion::allIsInstanceOf($subdefs, \media_subdef::class); - - $data = array_map([$this->hydrator, 'extract'], $subdefs); + $data = array_map([$this->hydrator, 'extract'], $this->normalizeToArray($subdefs)); $this->repository->save($data); } + /** + * @param \media_subdef|\media_subdef[] $subdefs + */ + public function delete($subdefs) + { + $subdefIds = array_map(function (\media_subdef $subdef) { + return [ + 'record_id' => $subdef->get_record_id(), + 'name' => $subdef->get_name(), + ]; + }, $this->normalizeToArray($subdefs)); + + $this->repository->delete($subdefIds); + } + public function clear() { $this->idMap = []; @@ -135,4 +143,20 @@ class MediaSubdefRepository return $instances; } + + /** + * @param \media_subdef|\media_subdef[] $subdefs + * @return array + */ + private function normalizeToArray($subdefs) + { + if (!is_array($subdefs) || !$subdefs instanceof \Traversable) { + $subdefs = [$subdefs]; + } elseif ($subdefs instanceof \Traversable) { + $subdefs = iterator_to_array($subdefs); + } + Assertion::allIsInstanceOf($subdefs, \media_subdef::class); + + return $subdefs; + } } diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php index 7150a3c989..1c61bb8ef2 100644 --- a/lib/classes/media/subdef.php +++ b/lib/classes/media/subdef.php @@ -158,39 +158,16 @@ class media_subdef extends media_abstract implements cache_cacheableInterface return; } - $sql = <<<'SQL' -SELECT subdef_id, name, file, width, height, mime, path, size, substit, created_on, updated_on, etag -FROM subdef -WHERE name = :name AND record_id = :record_id -SQL; + $data = self::getMediaSubdefRepository($this->app, $this->record->getDataboxId()) + ->findOneByRecordIdAndName($this->record->getRecordId(), $this->name); - $row = $this->getDataboxConnection()->fetchAssoc($sql, [ - 'record_id' => $this->record->getRecordId(), - 'name' => $this->name - ]); - - if ($row) { - $this->loadFromArray([ - 'width' => (int)$row['width'], - 'size' => (int)$row['size'], - 'height' => (int)$row['height'], - 'mime' => $row['mime'], - 'file' => $row['file'], - 'path' => p4string::addEndSlash($row['path']), - 'physically_present' => true, - 'is_substituted' => (bool)$row['substit'], - 'subdef_id' => (int)$row['subdef_id'], - 'updated_on' => $row['updated_on'], - 'created_on' => $row['created_on'], - 'etag' => $row['etag'] ?: null, - ]); + if ($data) { + $this->loadFromArray($data->toArray()); } elseif ($substitute === false) { throw new Exception_Media_SubdefNotFound($this->name . ' not found'); } - if (!$row) { - $this->markPhysicallyUnavailable(); - } + $this->loadFromArray([]); $this->set_data_to_cache($this->toArray()); } @@ -293,21 +270,16 @@ SQL; */ public function delete() { - $subdef_id = $this->subdef_id; $this->remove_file(); $connection = $this->getDataboxConnection(); - $connection->executeUpdate( - 'DELETE FROM subdef WHERE subdef_id = :subdef_id', - ['subdef_id' => $subdef_id] - ); - $connection->executeUpdate( 'DELETE FROM permalinks WHERE subdef_id = :subdef_id', - ['subdef_id'=>$subdef_id] + ['subdef_id' => $this->subdef_id] ); + self::getMediaSubdefRepository($this->app, $this->record->getDataboxId())->delete($this); $this->delete_data_from_cache(); $this->record->delete_data_from_cache(record_adapter::CACHE_SUBDEFS); } @@ -403,12 +375,7 @@ SQL; { $this->etag = $etag; - $this->getDataboxConnection()->executeUpdate( - 'UPDATE subdef SET etag = :etag WHERE subdef_id = :subdef_id', - [':subdef_id' => $this->subdef_id, ':etag' => $etag] - ); - - return $this; + return $this->save(); } /** @@ -418,17 +385,7 @@ SQL; { $this->is_substituted = !!$substit; - $this->getDataboxConnection()->executeUpdate( - 'UPDATE subdef SET substit = :substit, updated_on=NOW() WHERE subdef_id = :subdef_id', - [ - ':subdef_id' => $this->subdef_id, - ':substit' => $this->is_substituted - ] - ); - - $this->delete_data_from_cache(); - - return $this; + return $this->save(); } /** @@ -607,27 +564,10 @@ SQL; $media = $mediavorus->guess($this->getRealPath()); - $sql = <<<'SQL' -UPDATE subdef SET height = :height , width = :width, updated_on = NOW() -WHERE record_id = :record_id AND name = :name -SQL; - - $this->getDataboxConnection()->executeUpdate( - $sql, - [ - ':width' => $media->getWidth(), - ':height' => $media->getHeight(), - ':record_id' => $this->get_record_id(), - ':name' => $this->get_name(), - ] - ); - $this->width = $media->getWidth(); $this->height = $media->getHeight(); - $this->delete_data_from_cache(); - - return $this; + return $this->save(); } /** @@ -796,7 +736,6 @@ SQL; public function delete_data_from_cache($option = null) { - $this->setEtag(null); $databox = $this->get_record()->getDatabox(); $databox->delete_data_from_cache($this->get_cache_key($option)); @@ -873,4 +812,14 @@ SQL; return $this->app['phraseanet.h264']->getUrl($this->getRealPath()); } + + /** + * @return $this + */ + private function save() + { + self::getMediaSubdefRepository($this->app, $this->record->getDataboxId())->save($this); + + return $this; + } } From fca3146f91de57bab173da35329f5795cc8c8524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Fri, 22 Apr 2016 17:04:44 +0200 Subject: [PATCH 5/6] Remove subdef etag when marking physically unavailable --- lib/classes/media/subdef.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php index 1c61bb8ef2..ed9cf0ffe6 100644 --- a/lib/classes/media/subdef.php +++ b/lib/classes/media/subdef.php @@ -308,6 +308,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface $this->width = 256; $this->height = 256; $this->file = $this->getSubstituteFilename(); + $this->etag = null; $this->path = $this->app['root.path'] . '/www/assets/common/images/icons/substitution/'; $this->url = Url::factory('/assets/common/images/icons/substitution/' . $this->file); From d6b386662d92e1c08ecf94abd16406016ff75ad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Fri, 22 Apr 2016 19:18:29 +0200 Subject: [PATCH 6/6] fix listener to be called when refreshing Basket Workzone --- resources/www/prod/js/jquery.WorkZone.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/resources/www/prod/js/jquery.WorkZone.js b/resources/www/prod/js/jquery.WorkZone.js index 3f90ffe930..e7d1ef4de6 100644 --- a/resources/www/prod/js/jquery.WorkZone.js +++ b/resources/www/prod/js/jquery.WorkZone.js @@ -37,6 +37,12 @@ var p4 = p4 || {}; } activeBaskets(); + $('a.story_unfix').on('click', function () { + unfix($(this).attr('href')); + + return false; + }); + $('.basketTips').tooltip({ delay: 200 }); @@ -531,12 +537,6 @@ var p4 = p4 || {}; $(document).ready(function () { activeBaskets(); - $('a.story_unfix').on('click', function () { - unfix($(this).attr('href')); - - return false; - }); - p4.WorkZone = { 'Selection': new Selectable($('#baskets'), {selector: '.CHIM'}), 'refresh': refreshBaskets,