diff --git a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php index ca24737649..dcfa26ce46 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/RepositoriesServiceProvider.php @@ -14,6 +14,8 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Databox\CachedDataboxRepository; use Alchemy\Phrasea\Databox\DataboxFactory; +use Alchemy\Phrasea\Databox\DataboxFieldFactory; +use Alchemy\Phrasea\Databox\DbalDataboxFieldRepository; use Alchemy\Phrasea\Databox\DbalDataboxRepository; use Silex\Application; use Silex\ServiceProviderInterface; @@ -132,6 +134,10 @@ class RepositoriesServiceProvider implements ServiceProviderInterface return new CachedDataboxRepository($repository, $app['cache'], $appbox->get_cache_key($appbox::CACHE_LIST_BASES), $factory); }); + + $app['repo.fields.factory'] = $app->protect(function (\databox $databox) use ($app) { + return new DbalDataboxFieldRepository($databox->get_connection(), new DataboxFieldFactory($app, $databox)); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Databox/DataboxFieldFactory.php b/lib/Alchemy/Phrasea/Databox/DataboxFieldFactory.php new file mode 100644 index 0000000000..368fa04161 --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/DataboxFieldFactory.php @@ -0,0 +1,52 @@ +app = $app; + $this->databox = $databox; + } + + /** + * @param array $raw + * @return databox_field + */ + public function create(array $raw) + { + return new databox_field($this->app, $this->databox, $raw); + } + + /** + * @param array $rows + * @return databox_field[] + */ + public function createMany(array $rows) + { + $instances = []; + + foreach ($rows as $id => $raw) { + $instances[$id] = new databox_field($this->app, $this->databox, $raw); + } + + return $instances; + } +} diff --git a/lib/Alchemy/Phrasea/Databox/DataboxFieldRepositoryInterface.php b/lib/Alchemy/Phrasea/Databox/DataboxFieldRepositoryInterface.php new file mode 100644 index 0000000000..23e46df278 --- /dev/null +++ b/lib/Alchemy/Phrasea/Databox/DataboxFieldRepositoryInterface.php @@ -0,0 +1,20 @@ +connection = $connection; + $this->factory = $factory; + } + + public function find($id) + { + $row = $this->fetchRow($id); + if (is_array($row)) { + return $this->factory->create($id, $row); + } + + return null; + } + + public function findAll() + { + return $this->factory->createMany($this->fetchRows()); + } + + /** + * @param int $id + * @return false|array + * @throws \Doctrine\DBAL\DBALException + */ + private function fetchRow($id) + { + $result = $this->connection->executeQuery($this->getSQLForSingleRow(), ['id' => $id]); + $row = $result->fetch(\PDO::FETCH_ASSOC); + $result->closeCursor(); + + return $row; + } + + private function fetchRows() + { + $statement = $this->connection->executeQuery($this->getSQLForAllRows()); + $rows = $statement->fetchAll(\PDO::FETCH_ASSOC); + $statement->closeCursor(); + + return $rows; + } + + /** + * @return string + */ + private function getSQLForSingleRow() + { + static $sql; + + if (!$sql) { + $sql = $this->connection->createQueryBuilder() + ->select($this->getQuotedFields()) + ->from('metadatas_structure', 's') + ->where('id = :id') + ->getSQL(); + } + + return $sql; + } + + /** + * @return string + */ + private function getSQLForAllRows() + { + static $sql; + + if (!$sql) { + $sql = $this->connection->createQueryBuilder() + ->select($this->getQuotedFields()) + ->from('metadatas_structure', 's') + ->orderBy('sorter') + ->getSQL(); + } + + return $sql; + } + + /** + * @return array + */ + private function getQuotedFields() + { + $fields = []; + foreach (self::$columnNames as $field) { + $fields[] = $this->connection->quoteIdentifier($field); + }; + return $fields; + } +} diff --git a/lib/classes/databox/field.php b/lib/classes/databox/field.php index 47405bd503..cb48b852f0 100644 --- a/lib/classes/databox/field.php +++ b/lib/classes/databox/field.php @@ -14,12 +14,11 @@ use Alchemy\Phrasea\Core\Event\Record\Structure\FieldDeletedEvent; use Alchemy\Phrasea\Core\Event\Record\Structure\FieldEvent; use Alchemy\Phrasea\Core\Event\Record\Structure\FieldUpdatedEvent; use Alchemy\Phrasea\Core\Event\Record\Structure\RecordStructureEvents; +use Alchemy\Phrasea\Metadata\TagFactory; use Alchemy\Phrasea\Vocabulary; use Alchemy\Phrasea\Vocabulary\ControlProvider\ControlProviderInterface; use Alchemy\Phrasea\Metadata\Tag\Nosource; use Doctrine\DBAL\Driver\Connection; -use PHPExiftool\Driver\TagInterface; -use PHPExiftool\Driver\TagFactory; use PHPExiftool\Exception\TagUnknown; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; @@ -31,14 +30,10 @@ class databox_field implements cache_cacheableInterface /** @var Application */ protected $app; - /** - * @var databox - */ + /** @var databox */ protected $databox; - /** - * @var TagInterface - */ + /** DO NOT IMPORT, makes PHPSTORM HANG. PHPExiftool\Driver\TagInterface */ protected $tag; protected $name; @@ -53,23 +48,36 @@ class databox_field implements cache_cacheableInterface protected $separator; protected $thumbtitle; - /** - * @var array - */ + /** @var array */ protected $labels = []; - /** - * @var boolean - */ + /** @var boolean */ protected $Business; protected $renamed = false; - /** - * @var int - */ + /** @var int */ protected $sbas_id; + protected static $_instance = []; + protected static $knownDCES = [ + 'Contributor' => 'databox_Field_DCES_Contributor', + 'Coverage' => 'databox_Field_DCES_Coverage', + 'Creator' => 'databox_Field_DCES_Creator', + 'Date' => 'databox_Field_DCES_Date', + 'Description' => 'databox_Field_DCES_Description', + 'Format' => 'databox_Field_DCES_Format', + 'Identifier' => 'databox_Field_DCES_Identifier', + 'Language' => 'databox_Field_DCES_Language', + 'Publisher' => 'databox_Field_DCES_Publisher', + 'Relation' => 'databox_Field_DCES_Relation', + 'Rights' => 'databox_Field_DCES_Rights', + 'Source' => 'databox_Field_DCES_Source', + 'Subject' => 'databox_Field_DCES_Subject', + 'Title' => 'databox_Field_DCES_Title', + 'Type' => 'databox_Field_DCES_Type', + ]; + protected $dces_element; protected $Vocabulary; protected $VocabularyType; @@ -101,37 +109,25 @@ class databox_field implements cache_cacheableInterface const DCES_RIGHTS = 'Rights'; /** - * - * @param databox $databox - * @param int $id - * @return databox_field + * @param Application $app + * @param databox $databox + * @param array $row */ - protected function __construct(Application $app, databox $databox, $id) + public function __construct(Application $app, databox $databox, array $row) { $this->app = $app; $this->set_databox($databox); $this->sbas_id = $databox->get_sbas_id(); - $connbas = $this->get_connection(); - - $sql = "SELECT `thumbtitle`, `separator`, `dces_element`, `tbranch`, - `type`, `report`, `multi`, `required`, `readonly`, `indexable`, - `name`, `src`, `business`, `aggregable`, `VocabularyControlType`, - `RestrictToVocabularyControl`, `sorter`, - `label_en`, `label_fr`, `label_de`, `label_nl` - FROM metadatas_structure WHERE id=:id"; - - $stmt = $connbas->prepare($sql); - $stmt->execute([':id' => $id]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - if (!$row) { - throw new NotFoundHttpException(sprintf('Unable to find field in %s', $id)); - } - - $this->id = (int) $id; + $this->loadFromRow($row); + } + /** + * @param array $row + */ + protected function loadFromRow(array $row) + { + $this->id = (int)$row['id']; $this->original_src = $row['src']; $this->tag = self::loadClassFromTagName($row['src'], false); @@ -144,22 +140,22 @@ class databox_field implements cache_cacheableInterface } $this->name = $row['name']; - $this->indexable = (Boolean) $row['indexable']; - $this->readonly = (Boolean) $row['readonly']; - $this->required = (Boolean) $row['required']; - $this->multi = (Boolean) $row['multi']; - $this->Business = (Boolean) $row['business']; - $this->report = (Boolean) $row['report']; - $this->aggregable = (Int) $row['aggregable']; - $this->position = (Int) $row['sorter']; - $this->type = $row['type'] ? : self::TYPE_STRING; + $this->indexable = (bool)$row['indexable']; + $this->readonly = (bool)$row['readonly']; + $this->required = (bool)$row['required']; + $this->multi = (bool)$row['multi']; + $this->Business = (bool)$row['business']; + $this->report = (bool)$row['report']; + $this->aggregable = (int)$row['aggregable']; + $this->position = (int)$row['sorter']; + $this->type = $row['type'] ?: self::TYPE_STRING; $this->tbranch = $row['tbranch']; $this->VocabularyType = $row['VocabularyControlType']; - $this->VocabularyRestriction = !!$row['RestrictToVocabularyControl']; + $this->VocabularyRestriction = (bool)$row['RestrictToVocabularyControl']; - if ($row['dces_element']) { - $dc_class = 'databox_Field_DCES_' . $row['dces_element']; - $this->dces_element = new $dc_class(); + if (isset($row['dces_element'])) { + $class = self::$knownDCES[$row['dces_element']]; + $this->dces_element = new $class(); } $this->separator = self::checkMultiSeparator($row['separator'], $this->multi); @@ -167,8 +163,6 @@ class databox_field implements cache_cacheableInterface $this->thumbtitle = $row['thumbtitle']; $this->loadVocabulary(); - - return $this; } /** @@ -476,50 +470,33 @@ class databox_field implements cache_cacheableInterface /** * Get a PHPExiftool Tag from tagName * - * @param string $tagName - * @return \PHPExiftool\Driver\TagInterface - * @throws Exception_Databox_metadataDescriptionNotFound + * @param string $tagName + * @param bool $throwException + * @return object Makes phpstorm hangs \PHPExiftool\Driver\TagInterface */ public static function loadClassFromTagName($tagName, $throwException = true) { - $tagName = str_replace('/rdf:rdf/rdf:description/', '', $tagName); + $tagName = str_ireplace('/rdf:rdf/rdf:description/', '', $tagName); - if (trim($tagName) === '') { + if ('' === trim($tagName)) { + return new Nosource(); + } - $tag = new Alchemy\Phrasea\Metadata\Tag\Nosource(); - } elseif (strpos($tagName, 'Phraseanet:') === 0) { - - $tagName = str_replace('Phraseanet:', '', $tagName); - - $tagName = explode('-', $tagName); - $tagName = array_map('ucfirst', $tagName); - $tagName = implode('', $tagName); - - $classname = '\\Alchemy\\Phrasea\\Metadata\\Tag\\' . $tagName; - - if ( ! class_exists($classname)) { - if ($throwException) { - throw new Exception_Databox_metadataDescriptionNotFound(sprintf("tagname %s not found", $tagName)); - } else { - $tag = new Alchemy\Phrasea\Metadata\Tag\Nosource(); - } - } else { - $tag = new $classname(); - } - } else { - try { - $tag = TagFactory::getFromRDFTagname($tagName); - } catch (TagUnknown $e) { - if ($throwException) { - throw new NotFoundHttpException(sprintf("Tag %s not found", $tagName), $e); - } - $tag = new Alchemy\Phrasea\Metadata\Tag\Nosource(); + try { + return TagFactory::getFromRDFTagname($tagName); + } catch (TagUnknown $exception) { + if ($throwException) { + throw new NotFoundHttpException(sprintf("Tag %s not found", $tagName), $exception); } } - return $tag; + return new Nosource(); } + /** + * @param object $tag Actually \PHPExiftool\Driver\TagInterface but make PHPStorm hangs + * @return $this + */ public function set_tag($tag = null) { if ($tag === null) { @@ -532,8 +509,7 @@ class databox_field implements cache_cacheableInterface } /** - * - * @return TagInterface + * @return object Avoid PHPStorm stucks on 16k classes... \PHPExiftool\Driver\TagInterface */ public function get_tag() { @@ -588,7 +564,7 @@ class databox_field implements cache_cacheableInterface */ public function set_indexable($bool) { - $this->indexable = ! ! $bool; + $this->indexable = (bool)$bool; return $this; } @@ -614,7 +590,7 @@ class databox_field implements cache_cacheableInterface */ public function setVocabularyRestricted($boolean) { - $this->VocabularyRestriction = ! ! $boolean; + $this->VocabularyRestriction = (bool)$boolean; return $this; } @@ -627,7 +603,7 @@ class databox_field implements cache_cacheableInterface */ public function set_readonly($readonly) { - $this->readonly = ! ! $readonly; + $this->readonly = (bool)$readonly; return $this; } @@ -639,7 +615,7 @@ class databox_field implements cache_cacheableInterface */ public function set_business($boolean) { - $this->Business = ! ! $boolean; + $this->Business = (bool)$boolean; if ($this->Business) { $this->thumbtitle = null; @@ -663,7 +639,7 @@ class databox_field implements cache_cacheableInterface */ public function set_required($required) { - $this->required = ! ! $required; + $this->required = (bool)$required; return $this; } @@ -675,7 +651,7 @@ class databox_field implements cache_cacheableInterface */ public function set_report($report) { - $this->report = ! ! $report; + $this->report = (bool)$report; return $this; } @@ -723,7 +699,7 @@ class databox_field implements cache_cacheableInterface * @param boolean $multi * @return string */ - protected static function checkMultiSeparator($separator, $multi) + private static function checkMultiSeparator($separator, $multi) { if (! $multi) { return ''; @@ -1029,7 +1005,7 @@ class databox_field implements cache_cacheableInterface */ public function delete_data_from_cache($option = null) { - return $this->databox->delete_data_from_cache($this->get_cache_key($option)); + $this->databox->delete_data_from_cache($this->get_cache_key($option)); } private function loadVocabulary()