diff --git a/bin/console b/bin/console index 4fb292526e..03ba3846ad 100755 --- a/bin/console +++ b/bin/console @@ -16,6 +16,7 @@ namespace KonsoleKommander; * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ +use Alchemy\Phrasea\Command\BuildSubdefs; use Alchemy\Phrasea\Command\Plugin\ListPlugin; use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper; use Alchemy\Phrasea\Command\Setup\H264MappingGenerator; @@ -97,6 +98,7 @@ $cli->command(new CreateCollection('collection:create')); $cli->command(new RecordAdd('records:add')); $cli->command(new RescanTechnicalDatas('records:rescan-technical-datas')); $cli->command(new BuildMissingSubdefs('records:build-missing-subdefs')); +$cli->command(new BuildSubdefs('records:build-subdefs')); $cli->command(new AddPlugin()); $cli->command(new ListPlugin()); diff --git a/lib/Alchemy/Phrasea/Command/BuildMissingSubdefs.php b/lib/Alchemy/Phrasea/Command/BuildMissingSubdefs.php index 048fd68452..208d698c6b 100644 --- a/lib/Alchemy/Phrasea/Command/BuildMissingSubdefs.php +++ b/lib/Alchemy/Phrasea/Command/BuildMissingSubdefs.php @@ -44,9 +44,6 @@ class BuildMissingSubdefs extends Command $n = 0; foreach ($this->container['phraseanet.appbox']->get_databoxes() as $databox) { - - $subdefStructure = $databox->get_subdef_structure(); - $sql = 'SELECT record_id FROM record WHERE parent_record_id = 0'; $stmt = $databox->get_connection()->prepare($sql); $stmt->execute(); @@ -56,38 +53,14 @@ class BuildMissingSubdefs extends Command foreach ($rs as $row) { $record = $databox->get_record($row['record_id']); - try { - $record->get_hd_file(); - } catch (FileNotFoundException $e) { - continue; - } + $wanted_subdefs = $record->get_missing_subdefs(); - $group = $subdefStructure->getSubdefGroup($record->get_type()); + if (count($wanted_subdefs) > 0) { + $record->generate_subdefs($databox, $this->container, $wanted_subdefs); - if ($group) { - foreach ($group as $subdef) { - - $todo = false; - - if ( ! $record->has_subdef($subdef->get_name())) { - $todo = true; - } - if (in_array($subdef->get_name(), array('preview', 'thumbnail', 'thumbnailgif'))) { - try { - $sub = $record->get_subdef($subdef->get_name()); - if ( ! $sub->is_physically_present()) { - $todo = true; - } - } catch (\Exception_Media_SubdefNotFound $e) { - $todo = true; - } - } - - if ($todo) { - $record->generate_subdefs($databox, $this->container, array($subdef->get_name())); - $this->container['monolog']->addInfo("generate " . $subdef->get_name() . " for record " . $record->get_record_id()); - $n ++; - } + foreach ($wanted_subdefs as $subdef) { + $this->container['monolog']->addInfo("generate " .$subdef . " for record " . $record->get_record_id()); + $n ++; } } diff --git a/lib/Alchemy/Phrasea/Command/BuildSubdefs.php b/lib/Alchemy/Phrasea/Command/BuildSubdefs.php new file mode 100644 index 0000000000..bcf1abdb82 --- /dev/null +++ b/lib/Alchemy/Phrasea/Command/BuildSubdefs.php @@ -0,0 +1,171 @@ +setDescription('Build subviews for given subview names and record types'); + $this->addArgument('databox', InputArgument::REQUIRED, 'The databox id'); + $this->addArgument('type', InputArgument::REQUIRED, 'Types of the document to rebuild'); + $this->addArgument('subdefs', InputArgument::REQUIRED, 'Names of sub-definition to re-build'); + $this->addOption('max_record', 'max', InputOption::VALUE_OPTIONAL, 'Max record id'); + $this->addOption('min_record', 'min', InputOption::VALUE_OPTIONAL, 'Min record id'); + + return $this; + } + + /** + * {@inheritdoc} + */ + protected function doExecute(InputInterface $input, OutputInterface $output) + { + $availableTypes = array('document', 'audio', 'video', 'image', 'flash', 'map'); + + $typesOption = $input->getArgument('type'); + + $recordsType = explode(',', $typesOption); + $recordsType = array_filter($recordsType, function($type) use($availableTypes) { + return in_array($type, $availableTypes); + }); + + if (count($recordsType) === 0) { + $output->write(sprintf('Invalid records type provided %s', implode(', ', $availableTypes))); + return; + } + + $subdefsOption = $input->getArgument('subdefs'); + $subdefsName = explode(',', $subdefsOption); + + if (count($subdefsOption) === 0) { + $output->write('No subdef options provided'); + return; + } + + $sqlCount = " + SELECT COUNT(DISTINCT(r.record_id)) AS nb_records + FROM record r + INNER JOIN subdef s + ON (r.record_id = s.record_id) + WHERE s.name IN (?) + AND r.type IN (?) + "; + + $types = array(Connection::PARAM_STR_ARRAY, Connection::PARAM_STR_ARRAY); + $params = array($subdefsName, $recordsType); + + if (null !== $min = $input->getOption('min_record')) { + $sqlCount .= " AND (r.record_id >= ?)"; + + $params[] = (int) $min; + $types[] = \PDO::PARAM_INT; + } + if (null !== $max = $input->getOption('max_record')) { + $sqlCount .= " AND (r.record_id <= ?)"; + + $params[] = (int) $max; + $types[] = \PDO::PARAM_INT; + } + + list($sqlCount, $stmtParams) = SQLParserUtils::expandListParameters($sqlCount, $params, $types); + + $totalRecords = 0; + foreach ($this->container['phraseanet.appbox']->get_databoxes() as $databox) { + $connection = $databox->get_connection(); + $stmt = $connection->prepare($sqlCount); + $stmt->execute($stmtParams); + $row = $stmt->fetch(); + $totalRecords += $row['nb_records']; + } + + if ($totalRecords === 0) { + return; + } + + $progress = $this->getHelperSet()->get('progress'); + + $progress->start($output, $totalRecords); + + $progress->display(); + + $databox = $this->container['phraseanet.appbox']->get_databox($input->getArgument('databox')); + + $sql = " + SELECT DISTINCT(r.record_id) + FROM record r + INNER JOIN subdef s + ON (r.record_id = s.record_id) + WHERE s.name IN (?) + AND r.type IN (?) + "; + + $types = array(Connection::PARAM_STR_ARRAY, Connection::PARAM_STR_ARRAY); + $params = array($subdefsName, $recordsType); + + if ($min) { + $sql .= " AND (r.record_id >= ?)"; + + $params[] = (int) $min; + $types[] = \PDO::PARAM_INT; + } + if ($max) { + $sql .= " AND (r.record_id <= ?)"; + + $params[] = (int) $max; + $types[] = \PDO::PARAM_INT; + } + + list($sql, $stmtParams) = SQLParserUtils::expandListParameters($sql, $params, $types); + + $connection = $databox->get_connection(); + $stmt = $connection->prepare($sql); + $stmt->execute($stmtParams); + $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + foreach ($rows as $row) { + $output->write(sprintf(' (#%s)', $row['record_id'])); + + $record = new \record_adapter($this->container, $databox->get_sbas_id(), $row['record_id']); + + $subdefs = array_filter($record->get_subdefs(), function($subdef) use ($subdefsName) { + return in_array($subdef->get_name(), $subdefsName); + }); + + foreach ($subdefs as $subdef) { + $subdef->remove_file(); + } + + $record->generate_subdefs($databox, $this->container, $subdefsName); + + $stmt->closeCursor(); + + $progress->advance(); + } + + unset($rows, $record, $stmt, $connection); + + $progress->finish(); + } +} diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Tools.php b/lib/Alchemy/Phrasea/Controller/Prod/Tools.php index 53bc7cd94e..35ecfa416a 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Tools.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Tools.php @@ -90,10 +90,11 @@ class Tools implements ControllerProviderInterface $controllers->post('/image/', function (Application $app, Request $request) { $return = array('success' => true); + $force = $request->request->get('force_substitution') == '1'; + $selection = RecordsRequest::fromRequest($app, $request, false, array('canmodifrecord')); foreach ($selection as $record) { - $substituted = false; foreach ($record->get_subdefs() as $subdef) { if ($subdef->is_substituted()) { @@ -102,11 +103,12 @@ class Tools implements ControllerProviderInterface } } - if (!$substituted || $request->request->get('ForceThumbSubstit') == '1') { + if (!$substituted || $force) { $record->rebuild_subdefs(); } } + return $app->json($return); })->bind('prod_tools_image'); diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index d2a0b6a81c..182a71968a 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -1202,7 +1202,7 @@ class record_adapter implements record_Interface, cache_cacheableInterface * * @return record_adapter */ - public function rebuild_subdefs() + public function rebuild_subdefs() { $connbas = connection::getPDOConnection($this->app, $this->get_sbas_id()); $sql = 'UPDATE record SET jeton=(jeton | ' . JETON_MAKE_SUBDEF . ') WHERE record_id = :record_id'; @@ -1213,6 +1213,38 @@ class record_adapter implements record_Interface, cache_cacheableInterface return $this; } + public function get_missing_subdefs() + { + $databox = $this->get_databox(); + + try { + $this->get_hd_file(); + } catch (\Exception $e) { + return array(); + } + + $subDefDefinitions = $databox->get_subdef_structure()->getSubdefGroup($this->get_type()); + if (!$subDefDefinitions) { + return array(); + } + + $record = $this; + $wanted_subdefs = array_map(function($subDef) { + return $subDef->get_name(); + }, array_filter($subDefDefinitions, function($subDef) use ($record) { + return !$record->has_subdef($subDef->get_name()); + })); + + + $missing_subdefs = array_map(function($subDef) { + return $subDef->get_name(); + }, array_filter($this->get_subdefs(), function($subdef) { + return !$subdef->is_physically_present(); + })); + + return array_values(array_merge($wanted_subdefs, $missing_subdefs)); + } + /** * * @return record_adapter diff --git a/templates/web/prod/actions/Tools/index.html.twig b/templates/web/prod/actions/Tools/index.html.twig index b4a0fbbba5..63aecdf671 100644 --- a/templates/web/prod/actions/Tools/index.html.twig +++ b/templates/web/prod/actions/Tools/index.html.twig @@ -70,25 +70,20 @@ {% if nbThumbSubstitute > 0 %}
+ {{ 'Are you sure you want to rebuild the sub-definitions of selected records?' }} +