_fixed = Class_CodifThesaurusFixed::getAll(); } public function findFixed($key) { return isset($this->_fixed[$key]) ? $this->_fixed[$key] : null; } public function findThesaurusForCatalogue($catalogue_id) { return Class_CodifThesaurus::getLoader() ->findFirstBy(['id_origine'=> $catalogue_id, 'code' => Class_CodifThesaurus::fixedCodeOf('Domain')]); } public function collectForModelsUnderFixed($fixed_name, $models, $closure) { if (!isset($this->_fixed[$fixed_name])) return; foreach($models as $model) $closure($this->ensureForModelUnderRoot($model, $this->_fixed[$fixed_name])); } public function findLibraryNoveltyFor($library_id) { return ($library = Class_Bib::find((int)$library_id)) ? $this->_ensureLibraryNoveltyThesaurus($library) : null; } public function ensureForModelUnderRoot($model, $definition) { return ($root = Class_CodifThesaurus::findRootOfId($definition->getId(), $definition->getCode(), $definition->getLabel())) ? $root->getOrCreateChild($model->getId(), $model->getLibelle()) : null; } protected function _ensureLibraryNoveltyThesaurus($model) { return $this->ensureForModelUnderRoot($model, $this->_fixed['LibraryNovelty']); } protected function _ensureAnnexeNoveltyThesaurus($model) { return $this->ensureForModelUnderRoot($model, $this->_fixed['AnnexeNovelty']); } public function findForCustomField($field) { return Class_CodifThesaurus::findForCustomFieldMeta($field->getMeta()); } public function getOrCreateForCustomField($field) { return Class_CodifThesaurus::getOrCreateForCustomFieldMeta($field->getMeta()); } public function findForCustomFieldMeta($meta) { return Class_CodifThesaurus::getLoader() ->findFirstBy(['id_origine' => $meta->getId(), 'code' => Class_CodifThesaurus::fixedCodeOf('CustomField')]); } public function getOrCreateForCustomFieldMeta($meta) { return Class_CodifThesaurus::findCustomFieldsRoot() ->getOrCreateChild($meta->getId(), $meta->getLabel()); } public function findCustomFieldsRoot() { $definition = $this->_fixed['CustomField']; return Class_CodifThesaurus::findRootOfId($definition->getId(), $definition->getCode(), $definition->getLabel()); } public function findForItemLibraryNovelty($item) { if(!$library = $item->getBib()) return null; return ($item = $this->ensureForModelUnderRoot($library, $this->_fixed['LibraryNovelty'])) ? $item->getFacetteIndex() : ''; } public function findForItemAnnexeNovelty($item) { if(!$model = $item->getCodifAnnexe()) return null; return ($item = $this->ensureForModelUnderRoot($model, $this->_fixed['AnnexeNovelty'])) ? $item->getFacetteIndex() : ''; } public function countChildrenOf($id_thesaurus) { $where = sprintf('id_thesaurus like "%s%%" and LENGTH(id_thesaurus) > %s', $id_thesaurus, strlen($id_thesaurus)); return Class_CodifThesaurus::countBy(['where' => $where]); } public function findChildrenOfWith($id_thesaurus, $limit, $order) { $where = sprintf('id_thesaurus like "%s%%" and LENGTH(id_thesaurus) = %s', $id_thesaurus, (strlen($id_thesaurus) + 4)); return Class_CodifThesaurus::findAllBy(['where' => $where, 'limitPage' => $limit, 'order' => $order]); } public function findRootOfId($id, $code, $label) { if ($codif = Class_CodifThesaurus::findFirstBy(['id_thesaurus' => $id])) return $codif; $attributes = ['id_thesaurus' => $id, 'libelle' => $label, 'code' => $code]; $codif = Class_CodifThesaurus::newInstance($attributes); return $codif->save() ? $codif : null; } public function addFacetForSigb($facet_name, $facet_rules, $comm_sigb) { if (!Class_IntBib::findFirstBy(['comm_sigb' => $comm_sigb])) return; $parts = explode('$', trim($facet_rules)); if (2 !== count($parts)) return; $zone = $parts[0]; $label_field = $parts[1]; $rules = (new Class_CodifThesaurus_Rules()) ->setZone($zone) ->setLabelField($label_field); if (Class_CodifThesaurus::findFirstBy(['rules' => $rules->format()])) return ; Class_CodifThesaurus::newInstance(['libelle' => $facet_name, 'libelle_facette' => $facet_name, 'rule_zone' => $zone, 'rule_label_field' => $label_field]) ->save(); } public function getLibelleHierarchique($enreg) { if (!$enreg) return ''; if (!$parent = Class_CodifThesaurus::findParent($enreg->getIdThesaurus())) return $enreg->getLibelle(); if (strlen($parent->getIdThesaurus()) <= 8) return $parent->getLibelle() . ' : ' . $enreg->getLibelle(); return $this->getLibelleHierarchique($parent) . ' : ' . $enreg->getLibelle(); } public function findParent($id_thesaurus) { $parent_str=substr($id_thesaurus,0,strlen($id_thesaurus)-(4-strlen($id_thesaurus)%4)); if (!$parent_str) return null; $parent = Class_CodifThesaurus::findFirstBy(['where' => 'id_thesaurus like "'.$parent_str.'%" and LENGTH(id_thesaurus)<'.strlen($id_thesaurus), 'order' => 'id_thesaurus desc']); if (!$parent) return $this->findParent($parent_str); return $parent; } /** @return string */ public function findNextThesaurusChildId($code, $parentid_thesaurus) { Class_CodifThesaurus::clearCache(); $last_thesaurus = Class_CodifThesaurus::findFirstBy(['code' => $code, 'where' => 'id_thesaurus like "'.$parentid_thesaurus.'%"', 'order' => 'id_thesaurus desc']); if (!$last_thesaurus) return $parentid_thesaurus.'0001'; if (strlen($parentid_thesaurus) >=strlen($last_thesaurus->getIdThesaurus())) return $parentid_thesaurus.'0001'; return $this->incrementId(substr($last_thesaurus->getIdThesaurus(),0, strlen($parentid_thesaurus)+4)) ; } public function incrementId($id) { $last=base_convert(substr($id,strlen($id)-4), 36, 10); $first_part=substr($id,0,strlen($id)-4); $last++; $last = strtoupper(base_convert($last, 10, 36)); return $first_part.$this->getCodeSur4Chiffres($last,true); } public function findNextRacineCatalogue() { $last_thesaurus = Class_CodifThesaurus::findFirstBy(['where' => 'code like "catalogue" and LENGTH(id_thesaurus) in (1,8)', 'order' => 'id_thesaurus desc']); return $last_thesaurus ? $this->incrementId($last_thesaurus->getIdThesaurus()) : Class_CodifThesaurus::fixedIdOf('Domain') . '0001'; } public function deleteAllWithIdOrigineAndCode($id_origine, $code_thesaurus) { foreach (Class_CodifThesaurus::findAllBy(['id_origine' => $id_origine, 'code' => $code_thesaurus ]) as $thesaurus) Class_CodifThesaurus::deleteAllFrom($thesaurus); } public function deleteAllFrom($thesaurus) { if ($thesaurus && '' != $thesaurus->getIdThesaurus()) sqlExecute('delete from codif_thesaurus where id_thesaurus like "' . $thesaurus->getIdThesaurus() . '%"'); } /** * @param int * $return Class_CodifThesaurus */ public function findByIdOrigineAndCode($id_origine, $code_thesaurus) { return Class_CodifThesaurus::findFirstBy(['id_origine' => $id_origine, 'code' => $code_thesaurus ]); } public static function getCodeSur4Chiffres($code,$before=false) { $length=strlen($code); while (strlen($code) %4 != 0) { if ($before) $code = '0'.$code; else $code .='0'; } return $code; } public function getIndices($pere, $all = false ) { if(Class_CodifThesaurus::CODE_ROOT != $pere) { $pere = $this->getCodeSur4Chiffres($pere); $length = strlen($pere); return Class_CodifThesaurus::findAllBy(['where' => 'id_thesaurus like "'.$pere.'%" and LENGTH(id_thesaurus) in ('.($length+1).','.($length+4).')', 'order'=> 'id_thesaurus']); } $where = ''; // while search result do not handle item novelty correctly $to_exclude = [$this->fixedCodeOf('LibraryNovelty'), $this->fixedCodeOf('AnnexeNovelty')]; if (!$all) $to_exclude[] = $this->fixedCodeOf('Domain'); $where = sprintf('code not in ("%s") and ', implode('", "', $to_exclude)); $where .= 'LENGTH(id_thesaurus) in (1,4)'; return Class_CodifThesaurus::findAllBy(['where' => $where, 'order' => 'id_thesaurus']); } public function fixedCodeOf($name) { return isset($this->_fixed[$name]) ? $this->_fixed[$name]->getCode() : ''; } public function fixedIdOf($name) { return isset($this->_fixed[$name]) ? $this->_fixed[$name]->getId() : ''; } public function fixedLabelOf($name) { return isset($this->_fixed[$name]) ? $this->_fixed[$name]->getLabel() : ''; } public function getFacettesIndex() { return array_map(function($item) { return $item->getFacetteIndex(); }, Class_CodifThesaurus::getFacettesThesauri()); } public function getFacettesThesauri() { $filter = function($item) { return Class_CodifThesaurus::fixedIdOf('CustomField') != $item->getIdThesaurus(); }; $thesauri = array_filter(Class_CodifThesaurus::getIndices('root', true), $filter); foreach(Class_CodifThesaurus::findCustomFieldsRoot()->getChildren() as $item) $thesauri[] = $item; return $thesauri; } public function findChildrenOf($parent) { if (!$parent || !$id_thesaurus = $parent->getIdThesaurus()) return []; $where = sprintf('id_thesaurus like "%s%%" and LENGTH(id_thesaurus) = %s', $id_thesaurus, strlen($id_thesaurus) + 4); return Class_CodifThesaurus::findAllBy(['where' => $where, 'order' => 'libelle']); } public function getFacetGroup($facet) { return substr($facet, 0, $this->isCustomFieldsFacet($facet) ? 9 : 5); } protected function isCustomFieldsFacet($facet) { return $this->startsWith($facet, $this->getCustomFieldsFacetPrefix()); } protected function startsWith($value, $prefix) { return $prefix == substr($value, 0, strlen($prefix)); } protected function getCustomFieldsFacetPrefix() { if (!isset($this->_customfields_facet_prefix)) return $this->_customfields_facet_prefix = Class_CodifThesaurus::CODE_FACETTE . Class_CodifThesaurus::fixedIdOf('CustomField'); return $this->_customfields_facet_prefix; } public function suggestFrom($recherche, $mode, $limite_resultat, $theme) { if (!$req = $this->_suggestQueryFor((int)$mode, $theme, $recherche, $limite_resultat)) return []; $resultat=fetchAll($req); if (!$resultat) return []; foreach($resultat as $enreg) { $thesaurus = Class_CodifThesaurus::find($enreg["id"]); $libelle = Class_CodifThesaurus::getLibelleHierarchique($thesaurus); $liste[] = [$enreg["id_thesaurus"], $enreg["id_origine"]." : ".$libelle]; } return $liste; } protected function _suggestQueryFor($mode, $parent, $term, $limit) { $parent_clause = $this->_fieldStartsWith('id_thesaurus', $parent); if (static::SUGGEST_HIERARCHY_CONTAINS == $mode) { return (3 <= strlen($term)) ? $this->_orderAndLimit("select distinct(id), id, id_thesaurus, id_origine " ."from codif_thesaurus where id_thesaurus regexp (select group_concat(concat(id_thesaurus,'.*') separator '|') from codif_thesaurus where ". $parent_clause ." and id_origine is not null and " . $this->_fieldContains('libelle', $term) . ")", $limit) : null; } $basic_select = "select id, id_thesaurus, id_origine from codif_thesaurus where ". $parent_clause; if (static::SUGGEST_LABEL_STARTS_WITH == $mode) return $this->_orderAndLimit($basic_select . ' and ' . $this->_fieldStartsWith('libelle', $term), $limit); if (static::SUGGEST_LABEL_CONTAINS == $mode) return $this->_orderAndLimit($basic_select . ' and ' . $this->_fieldContains('libelle', $term), $limit); if (static::SUGGEST_INDEX_STARTS_WITH == $mode) return $this->_orderAndLimit($basic_select . ' and ' . $this->_fieldStartsWith('id_origine', $term), $limit); } protected function _orderAndLimit($sql, $limit) { return $sql . ' order by id_thesaurus limit ' . $limit; } protected function _fieldStartsWith($field, $value) { return $this->_like($field, addslashes($value) . '%'); } protected function _fieldContains($field, $value) { return $this->_like($field, '%' . addslashes($value) . '%'); } protected function _like($field, $clause) { return $field . ' like \''. $clause . '\''; } public function getDynamicCodes() { $dynamic_facets = Class_CodifThesaurus::findAllBy(['rules not' => null, 'code not' => null, 'id_thesaurus not' => null]); $params = []; foreach($dynamic_facets as $facet) $params [] = $facet->getCode(); return array_unique($params); } public function root() { return Class_CodifThesaurus::newInstance(); } public function newIdThesaurusForLabel($label) { $id = substr(strtoupper($label), 0, Class_CodifThesaurus::ID_KEY_LENGTH); if (strlen($id) == Class_CodifThesaurus::ID_KEY_LENGTH && !Class_CodifThesaurus::findFirstBy(['id_thesaurus' => $id])) return $id; $label = substr(strtoupper($label), 0, 3); $suffixes = array_merge(range(0, 9), range('a', 'z')); while(!empty($suffixes)) { $suffix = strtoupper(array_shift($suffixes)); $id = sprintf("%'".$suffix."-4s", $label); if (!Class_CodifThesaurus::findFirstBy(['id_thesaurus' => $id])) return $id; } } public function withDynamicFacetsHavingIdFieldDo($closure) { (new Storm_Model_Collection(Class_CodifThesaurus::findAllBy(['rules not' => null, 'rules not' => '', 'id_thesaurus not' => null, 'order' => 'libelle']))) ->select('hasRuleIdField') ->eachDo($closure); } } class Class_CodifThesaurus extends Storm_Model_Abstract { use Trait_Translator, Trait_MemoryCleaner, Trait_Facetable, Trait_TreeNode; const CODE_ROOT = 'root', COLUMN_ORIGIN_SIZE = 20, ID_KEY_LENGTH = 4, CODE_FACETTE = 'H'; protected $_loader_class = 'CodifThesaurusLoader'; protected $_table_name = 'codif_thesaurus'; protected $_table_primary = 'id'; protected $_default_attribute_values = ['libelle' => '', 'libelle_facette' => '', 'id_thesaurus' => null, 'id_origine' => null, 'rules' => null, 'code' => null]; protected $_rules; public function __construct() { parent::__construct(); $this->_rules = new Class_CodifThesaurus_Rules(); } public function initializeAttributes($datas) { parent::initializeAttributes($datas); $this->_rules->initialize($this->getRules()); return $this; } public function beforeSave() { $this->setRules($this->_rules->format()); } public function getRuleZone() { return $this->_rules->getZone(); } public function setRuleZone($zone) { $this->_rules->setZone($zone); return $this; } public function getRuleLabelField() { return $this->_rules->getLabelField(); } public function setRuleLabelField($field) { $this->_rules->setLabelField($field); return $this; } public function getRuleIdField() { return $this->_rules->getIdField(); } public function setRuleIdField($field) { $this->_rules->setIdField($field); return $this; } public function setRuleLabelStartPos($value) { $this->_rules->setLabelStartPos($value); return $this; } public function setRuleFilterField($field) { $this->_rules->setFilterField($field); return $this; } public function setRuleFilterValue($field) { $this->_rules->setFilterValue($field); return $this; } public function setRuleLabelLength($value) { $this->_rules->setLabelLength($value); return $this; } public function getRuleLabelLength() { return $this->_rules->getLabelLength(); } public function getRuleLabelStartPos() { return $this->_rules->getLabelStartPos(); } public function rulesTruncateLabels($labels) { return $this->_rules->truncateLabels($labels); } public function getRulesAsArray() { return ['rule_zone' => $this->_rules->getZone(), 'rule_label_field' => $this->_rules->getLabelField(), 'rule_id_field' => $this->_rules->getIdField(), 'rule_label_start_pos' => $this->_rules->getLabelStartPos(), 'rule_label_length' => $this->_rules->getLabelLength(), 'rule_filter_field' => $this->_rules->getFilterField(), 'rule_filter_value' => $this->_rules->getFilterValue()]; } public function withLabelAndIdRulesDo($closure) { return $this->_rules->withLabelAndIdDo($closure); } public function getListeSuggestion($recherche, $mode, $limite_resultat, $theme) { return $this->getLoader()->suggestFrom($recherche, $mode, $limite_resultat, $theme); } public function getLibelleFacette() { return $this->_get('libelle_facette') && $this->_get('libelle_facette') != '' ? $this->_get('libelle_facette') : $this->getLibelle(); } public function asFacet() { return $this->getFacetteIndex(); } public function getFacetteIndex() { return self::CODE_FACETTE . $this->getIdThesaurus(); } public function newChildEntry() { $code = $this->getCode(); return Class_CodifThesaurus::getLoader()->newInstance(['code' => $code, 'id_thesaurus' => Class_CodifThesaurus::getLoader()->findNextThesaurusChildId( $code, $this->getIdThesaurus())]); } public function getOrCreateChild($id_origine, $label) { if (!$entry = $this->getChild($id_origine)) $entry = $this->newChildEntry(); if ($label == $entry->getLibelle()) return $entry; $entry ->updateAttributes(['id_origine' => $id_origine, 'libelle' => $label]); return $entry->save() ? $entry : null; } public function getOrCreateChildren($labels) { return array_map( function($label) { return $this->getOrCreateChild(strtoupper($label), $label); }, array_filter($labels)); } public function getChild($id_origine) { return Class_CodifThesaurus::getLoader() ->findFirstBy(['code' => $this->getCode(), 'id_origine' => mb_substr($id_origine, 0, self::COLUMN_ORIGIN_SIZE, 'UTF-8')]); } public function withRulesDo($closure) { if ((!$this->_rules->getZone()) || (!$this->_rules->getLabelField())) return; return $closure($this->_rules); } public function rulesCanHandle($reader) { return $this->_rules->canHandle($reader); } public function validate() { $this->_validateIdThesaurus(); $this->checkAttribute('libelle', '' != $this->getLibelle(), $this->_('Vous devez définir le libellé')); $this->check($this->_rules->isValid(), $this->_rules->getErrorMessage()); } protected function _validateIdThesaurus() { $my_key = substr($this->getIdThesaurus(), -self::ID_KEY_LENGTH); $empty_key = str_repeat('0', self::ID_KEY_LENGTH); $this->checkAttribute('id_thesaurus', $my_key != $empty_key, $this->_('Nombre maximum d\'élément à ce niveau déjà atteint (%s)', str_repeat('Z', self::ID_KEY_LENGTH))); } public function deleteMeAndMyChildren() { $this->cleanRecords(); $this->getLoader()->deleteAllFrom($this); return $this; } public function cleanRecords() { $facets = []; foreach($this->getLoader()->findChildrenOf($this) as $child) $facets[] = $child->getFacetteIndex(); if (empty($facets)) return $this; $facets = implode(' ', $facets); while ($records = Class_Notice::findAllBy(['where' => 'match(facettes) against(\'' . $facets . '\')', 'limit' => 100])) { foreach($records as $record) { $record->deleteFacettes($facets) ->save(); } $this->_cleanMemory(); } return $this; } public function getOrCreateCustomFieldValueChild($value) { return $this->getOrCreateChild($this->getLoader()->fixedIdOf('CustomField') . hash('crc32b', $value), $value); } public function getChildren() { return $this->getLoader()->findChildrenOf($this); } public function getParentChildren() { return array_filter($this->getChildren(), function ($children) { return ($children->hasChildren()); }); } public function getChildrenItems() { return array_filter($this->getChildren(), function ($children) { return (!$children->hasChildren()); }); } public function getParent() { return $this->getLoader()->findParent($this->getIdThesaurus()); } public function getParentId() { return $this->getParent() ? $this->getParent()->getId() : null; } public function getTitre() { return $this->getLibelleFacette(); } public function numberOfChildrens() { return $this->getLoader()->countChildrenOf($this->getIdThesaurus()); } public function isNotRoot() { return strlen($this->getIdThesaurus()) > Class_CodifThesaurus::ID_KEY_LENGTH; } public function getNodes() { if($this->isNew()) return $this->getLoader()->getIndices('root', true); return $this->getParentChildren(); } public function getLeaves($params) { if($this->isNew()) return []; return $this->getLoader()->findChildrenOfWith($this->getIdThesaurus(), $params['limitPage'], $params['order']); } public function numberOfLeaves() { return count($this->getChildrenItems()); } public function recursiveNumberOfChildren() { return $this->isNew() ? 0 : $this->numberOfChildrens(); } public function authoritiesIndexSystems() { if (!$this->getRuleIdField()) return []; $systems = []; foreach(Class_IntProfilDonnees::findAllOfTypeAuthority() as $profile) $systems = $this->_addIndexSystemsFromPrefsInto($profile->getIndexSystemsPrefs(), $systems); return array_filter($systems); } protected function _addIndexSystemsFromPrefsInto($prefs, $systems) { foreach(Class_Notice_AuthorityIndexSystem::collectionFromPrefs($prefs) ->filterByThesaurus($this) as $system) $systems[] = $system; return $systems; } }