Skip to content

Commit f91fca9

Browse files
committed
Added SuggestListStrategy
1 parent 65b3c81 commit f91fca9

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
/**
3+
* wCMF - wemove Content Management Framework
4+
* Copyright (C) 2005-2020 wemove digital solutions GmbH
5+
*
6+
* Licensed under the terms of the MIT License.
7+
*
8+
* See the LICENSE file distributed with this work for
9+
* additional information.
10+
*/
11+
namespace wcmf\lib\presentation\control\lists\impl;
12+
13+
use wcmf\lib\io\Cache;
14+
use wcmf\lib\config\ConfigurationException;
15+
use wcmf\lib\core\ObjectFactory;
16+
use wcmf\lib\model\StringQuery;
17+
use wcmf\lib\persistence\BuildDepth;
18+
use wcmf\lib\persistence\ObjectId;
19+
use wcmf\lib\presentation\control\lists\ListStrategy;
20+
use wcmf\lib\util\StringUtil;
21+
22+
/**
23+
* SuggestListStrategy implements a list of suggestions that is retrieved
24+
* from all existing values of one entity attribute, where the keys and the
25+
* values are the values.
26+
*
27+
* Configuration examples:
28+
* @code
29+
* // list all existing author names
30+
* {"type":"suggest","attributes":["Author.name"]}
31+
*
32+
* // list all existing author names and book titles
33+
* {"type":"suggest","attributes":["Author.name", "Book.title"]}
34+
*
35+
* // list all authors with name starting with A (see StringQuery)
36+
* {"type":"suggest","attributes":["Author.name"],"query":"Author.name LIKE 'A%'"}
37+
*
38+
* // list all author names and book titles with different queries (see StringQuery)
39+
* {"type":"suggest","attributes":["Author.name", "Book.title"],"query":{"Author":"Author.name LIKE 'A%'","Book":"Book.title LIKE 'A%'"}}
40+
*
41+
* @endcode
42+
*
43+
* @author ingo herwig <[email protected]>
44+
*/
45+
class SuggestListStrategy implements ListStrategy {
46+
47+
const CACHE_SECTION = 'suggestliststrategy';
48+
49+
protected $cache = null;
50+
51+
/**
52+
* Constructor
53+
* @param $dynamicCache Cache instance
54+
*/
55+
public function __construct(Cache $dynamicCache) {
56+
$this->cache = $dynamicCache;
57+
}
58+
59+
/**
60+
* @see ListStrategy::getList
61+
* $options is an associative array with keys 'attributes' and 'query' (optional)
62+
*/
63+
public function getList($options, $valuePattern=null, $key=null, $language=null) {
64+
if (!isset($options['attributes'])) {
65+
throw new ConfigurationException("No 'attributes' given in list options: "+StringUtil::getDump($options));
66+
}
67+
$localization = ObjectFactory::getInstance('localization');
68+
$persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
69+
70+
$attributes = $options['attributes'];
71+
72+
$hasQuery = (isset($options['query']) && !empty($options['query'])) || $valuePattern;
73+
$needsTranslation = $language != null && $language != $localization->getDefaultLanguage();
74+
75+
// set cache id for unfiltered result
76+
$cacheId = !$hasQuery ? hash('sha256', join('+', [json_encode($options), $valuePattern, $language])) : null;
77+
78+
$list = [];
79+
if ($cacheId && $this->cache->exists(self::CACHE_SECTION, $cacheId)) {
80+
$list = $this->cache->get(self::CACHE_SECTION, $cacheId);
81+
}
82+
else {
83+
foreach ($attributes as $attribute) {
84+
list($typeName, $attributeName) = $this->getTypeAndAttribute($attribute);
85+
$query = new StringQuery($typeName);
86+
if ($hasQuery) {
87+
$queryValue = $options['query'];
88+
if (is_string($queryValue)) {
89+
$query->setConditionString($queryValue);
90+
}
91+
else if (isset($queryValue[$typeName])) {
92+
$query->setConditionString($queryValue[$typeName]);
93+
}
94+
}
95+
// add display value query
96+
if ($valuePattern) {
97+
$dbPattern = preg_replace('/^\/|\/$/', '', $valuePattern);
98+
$valuePatterns = [];
99+
$mapper = $persistenceFacade->getMapper($typeName);
100+
foreach ($mapper->getProperties()['displayValues'] as $displayValue) {
101+
$valuePatterns[] = $typeName.'.'.$displayValue.' REGEXP '.$mapper->quoteValue($dbPattern);
102+
}
103+
if (sizeof($valuePatterns) > 0) {
104+
$existingQuery = $query->getConditionString();
105+
$query->setConditionString($existingQuery.(strlen($existingQuery) > 0 ? ' AND ' : ' ').'('.join(' OR ', $valuePatterns).')');
106+
}
107+
}
108+
$objects = $query->execute(BuildDepth::SINGLE);
109+
foreach ($objects as $object) {
110+
if ($needsTranslation) {
111+
$object = $localization->loadTranslation($object, $language);
112+
}
113+
$value = $object->getValue($attributeName);
114+
if (strlen($value) > 0) {
115+
$list[$value] = $value;
116+
}
117+
}
118+
}
119+
natsort($list);
120+
$list = array_unique($list);
121+
if ($cacheId) {
122+
$this->cache->put(self::CACHE_SECTION, $cacheId, $list);
123+
}
124+
}
125+
return $list;
126+
}
127+
128+
/**
129+
* @see ListStrategy::isStatic
130+
*/
131+
public function isStatic($options) {
132+
return false;
133+
}
134+
135+
/**
136+
* Derive type and attribute from a string of the form type.attribute
137+
* @param mixed $typeAttr
138+
* @return array of type name and attribute name
139+
*/
140+
protected function getTypeAndAttribute($typeAttr) {
141+
$persistenceFacade = ObjectFactory::getInstance('persistenceFacade');
142+
143+
$parts = explode('.', $typeAttr);
144+
$attribute = array_pop($parts);
145+
$type = join('.', $parts);
146+
if ($persistenceFacade->isKnownType($type)) {
147+
$mapper = $persistenceFacade->getMapper($type);
148+
if ($mapper->hasAttribute($attribute)) {
149+
return [$type, $attribute];
150+
}
151+
}
152+
throw new ConfigurationException("Could not resolve \"{$typeAttr}\"");
153+
}
154+
}
155+
?>

0 commit comments

Comments
 (0)