diff --git a/lib/classes/caption/Field/Value.php b/lib/classes/caption/Field/Value.php index 28e259d713..d216de6f78 100644 --- a/lib/classes/caption/Field/Value.php +++ b/lib/classes/caption/Field/Value.php @@ -15,6 +15,9 @@ use Alchemy\Phrasea\Vocabulary; class caption_Field_Value implements cache_cacheableInterface { + const RETRIEVE_VALUES = true; + const DONT_RETRIEVE_VALUES = false; + /** @var int */ protected $id; @@ -55,16 +58,19 @@ class caption_Field_Value implements cache_cacheableInterface * @param databox_field $databox_field * @param record_adapter $record * @param mixed $id + * @param bool $retrieveValues * @return \caption_Field_Value */ - public function __construct(Application $app, databox_field $databox_field, record_adapter $record, $id) + public function __construct(Application $app, databox_field $databox_field, record_adapter $record, $id, $retrieveValues = self::RETRIEVE_VALUES) { $this->id = (int) $id; $this->databox_field = $databox_field; $this->record = $record; $this->app = $app; - $this->retrieveValues(); + if($retrieveValues == self::RETRIEVE_VALUES) { + $this->retrieveValues(); + } } public function getQjs() @@ -72,6 +78,53 @@ class caption_Field_Value implements cache_cacheableInterface return $this->qjs; } + public function injectValues($value, $VocabularyType, $VocabularyId) + { + $this->value = StringHelper::crlfNormalize($value); + + try { + $this->VocabularyType = $VocabularyType ? Vocabulary\Controller::get($this->app, $VocabularyType) : null; + $this->VocabularyId = $VocabularyId; + } catch (\InvalidArgumentException $e) { + + } + + if ($this->VocabularyType) { + /** + * Vocabulary Control has been deactivated + */ + if ( ! $this->databox_field->getVocabularyControl()) { + $this->removeVocabulary(); + } + /** + * Vocabulary Control has changed + */ + elseif ($this->databox_field->getVocabularyControl()->getType() !== $this->VocabularyType->getType()) { + $this->removeVocabulary(); + } + /** + * Current Id is not available anymore + */ + elseif ( ! $this->VocabularyType->validate($this->VocabularyId)) { + $this->removeVocabulary(); + } + /** + * String equivalence has changed + */ + elseif ($this->VocabularyType->getValue($this->VocabularyId) !== $this->value) { + $this->set_value($this->VocabularyType->getValue($this->VocabularyId)); + } + } + + $datas = [ + 'value' => $this->value, + 'vocabularyId' => $this->VocabularyId, + 'vocabularyType' => $this->VocabularyType ? $this->VocabularyType->getType() : null, + ]; + + $this->set_data_to_cache($datas); + } + protected function retrieveValues() { try { @@ -95,47 +148,13 @@ class caption_Field_Value implements cache_cacheableInterface $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); - $this->value = $row ? StringHelper::crlfNormalize($row['value']) : null; - - try { - $this->VocabularyType = $row['VocabularyType'] ? Vocabulary\Controller::get($this->app, $row['VocabularyType']) : null; - $this->VocabularyId = $row['VocabularyId']; - } catch (\InvalidArgumentException $e) { - + if($row) { + $this->injectValues($row['value'], $row['VocabularyType'], $row['VocabularyId']); } - - if ($this->VocabularyType) { - /** - * Vocabulary Control has been deactivated - */ - if ( ! $this->databox_field->getVocabularyControl()) { - $this->removeVocabulary(); - } - /** - * Vocabulary Control has changed - */ elseif ($this->databox_field->getVocabularyControl()->getType() !== $this->VocabularyType->getType()) { - $this->removeVocabulary(); - } - /** - * Current Id is not available anymore - */ elseif ( ! $this->VocabularyType->validate($this->VocabularyId)) { - $this->removeVocabulary(); - } - /** - * String equivalence has changed - */ elseif ($this->VocabularyType->getValue($this->VocabularyId) !== $this->value) { - $this->set_value($this->VocabularyType->getValue($this->VocabularyId)); - } + else { + $this->injectValues(null, null, null); } - $datas = [ - 'value' => $this->value, - 'vocabularyId' => $this->VocabularyId, - 'vocabularyType' => $this->VocabularyType ? $this->VocabularyType->getType() : null, - ]; - - $this->set_data_to_cache($datas); - return $this; } diff --git a/lib/classes/caption/field.php b/lib/classes/caption/field.php index fdd2bd658d..ecd4ac9bf2 100644 --- a/lib/classes/caption/field.php +++ b/lib/classes/caption/field.php @@ -14,6 +14,9 @@ use Doctrine\DBAL\Driver\Statement; class caption_field implements cache_cacheableInterface { + const RETRIEVE_VALUES = true; + const DONT_RETRIEVE_VALUES = false; + /** * @var databox_field */ @@ -33,33 +36,44 @@ class caption_field implements cache_cacheableInterface protected static $localCache = []; /** - * @param Application $app - * @param databox_field $databox_field + * @param Application $app + * @param databox_field $databox_field * @param record_adapter $record + * @param bool $retrieveValues * * @return caption_field */ - public function __construct(Application $app, databox_field $databox_field, \record_adapter $record) + public function __construct(Application $app, databox_field $databox_field, \record_adapter $record, $retrieveValues = self::RETRIEVE_VALUES) { $this->app = $app; $this->record = $record; $this->databox_field = $databox_field; $this->values = []; - $rs = $this->get_metadatas_ids(); + if($retrieveValues == self::RETRIEVE_VALUES) { + $rs = $this->get_metadatas_ids(); - foreach ($rs as $row) { - $this->values[$row['id']] = new caption_Field_Value($this->app, $databox_field, $record, $row['id']); + foreach ($rs as $row) { + $this->values[$row['id']] = new caption_Field_Value($this->app, $databox_field, $record, $row['id']); - // Inconsistent, should not happen - if ( ! $databox_field->is_multi()) { - break; + // Inconsistent, should not happen + if (!$databox_field->is_multi()) { + break; + } } } return $this; } + /** + * @param caption_Field_Value[] $values + */ + public function injectValues($values) + { + $this->values = $values; + } + protected function get_metadatas_ids() { try { @@ -73,7 +87,7 @@ class caption_field implements cache_cacheableInterface $sql = 'SELECT id FROM metadatas WHERE record_id = :record_id AND meta_struct_id = :meta_struct_id'; $params = [ - ':record_id' => $this->record->get_record_id() + ':record_id' => $this->record->getRecordId() , ':meta_struct_id' => $this->databox_field->get_id() ]; diff --git a/lib/classes/caption/record.php b/lib/classes/caption/record.php index 6dfeac7f92..740e21ee2b 100644 --- a/lib/classes/caption/record.php +++ b/lib/classes/caption/record.php @@ -47,7 +47,7 @@ class caption_record implements caption_interface, cache_cacheableInterface public function __construct(Application $app, \record_adapter $record, databox $databox) { $this->app = $app; - $this->sbas_id = $record->get_sbas_id(); + $this->sbas_id = $record->getDataboxId(); $this->record = $record; $this->databox = $databox; } @@ -78,12 +78,12 @@ class caption_record implements caption_interface, cache_cacheableInterface try { $fields = $this->get_data_from_cache(); } catch (\Exception $e) { - $sql = "SELECT m.id as meta_id, s.id as structure_id - FROM metadatas m, metadatas_structure s - WHERE m.record_id = :record_id AND s.id = m.meta_struct_id - ORDER BY s.sorter ASC"; + $sql = "SELECT m.id AS meta_id, s.id AS structure_id, value, VocabularyType, VocabularyId" + . " FROM metadatas m, metadatas_structure s" + . " WHERE m.record_id = :record_id AND s.id = m.meta_struct_id" + . " ORDER BY s.sorter ASC"; $stmt = $this->databox->get_connection()->prepare($sql); - $stmt->execute([':record_id' => $this->record->get_record_id()]); + $stmt->execute([':record_id' => $this->record->getRecordId()]); $fields = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt->closeCursor(); if ($fields) { @@ -95,11 +95,55 @@ class caption_record implements caption_interface, cache_cacheableInterface if ($fields) { $databox_descriptionStructure = $this->databox->get_meta_structure(); - foreach ($fields as $row) { - $databox_field = $databox_descriptionStructure->get_element($row['structure_id']); - $metadata = new caption_field($this->app, $databox_field, $this->record); - $rec_fields[$databox_field->get_id()] = $metadata; + // first group values by field + $caption_fields = []; + foreach ($fields as $row) { + $structure_id = $row['structure_id']; + if(!array_key_exists($structure_id, $caption_fields)) { + $caption_fields[$structure_id] = [ + 'db_field' => $databox_descriptionStructure->get_element($structure_id), + 'values' => [] + ]; + } + + if (count($caption_fields[$structure_id]['values']) > 0 && !$caption_fields[$structure_id]['db_field']->is_multi()) { + // Inconsistent, should not happen + continue; + } + + // build an EMPTY caption_Field_Value + $cfv = new caption_Field_Value( + $this->app, + $caption_fields[$structure_id]['db_field'], + $this->record, + $row['meta_id'], + caption_Field_Value::DONT_RETRIEVE_VALUES // ask caption_Field_Value "no n+1 sql" + ); + + // inject the value we already know + $cfv->injectValues($row['value'], $row['VocabularyType'], $row['VocabularyId']); + + // add the value to the field + $caption_fields[$structure_id]['values'][] = $cfv; + } + + // now build a "caption_field" with already known "caption_Field_Value"s + foreach($caption_fields as $structure_id => $caption_field) { + + // build an EMPTY caption_field + $cf = new caption_field( + $this->app, + $caption_field['db_field'], + $this->record, + caption_field::DONT_RETRIEVE_VALUES // ask caption_field "no n+1 sql" + ); + + // inject the value we already know + $cf->injectValues($caption_field['values']); + + // add the field to the fields + $rec_fields[$structure_id] = $cf; } } $this->fields = $rec_fields; @@ -248,7 +292,7 @@ class caption_record implements caption_interface, cache_cacheableInterface */ public function get_data_from_cache($option = null) { - return $this->record->get_databox()->get_data_from_cache($this->get_cache_key($option)); + return $this->record->getDatabox()->get_data_from_cache($this->get_cache_key($option)); } /** @@ -261,7 +305,7 @@ class caption_record implements caption_interface, cache_cacheableInterface */ public function set_data_to_cache($value, $option = null, $duration = 0) { - return $this->record->get_databox()->set_data_to_cache($value, $this->get_cache_key($option), $duration); + return $this->record->getDatabox()->set_data_to_cache($value, $this->get_cache_key($option), $duration); } /** @@ -274,6 +318,6 @@ class caption_record implements caption_interface, cache_cacheableInterface { $this->fields = null; - return $this->record->get_databox()->delete_data_from_cache($this->get_cache_key($option)); + return $this->record->getDatabox()->delete_data_from_cache($this->get_cache_key($option)); } }