@@ -25,7 +25,7 @@ |
||
25 | 25 | |
26 | 26 | public function __construct() { |
27 | 27 | foreach ($this->_buildInCaches as $_name) { |
28 | - $name = 'Saito\Cache\\' . $_name; |
|
28 | + $name = 'Saito\Cache\\'.$_name; |
|
29 | 29 | $this->add(new $name); |
30 | 30 | } |
31 | 31 | \CakeEventManager::instance()->attach($this); |
@@ -1,174 +1,174 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\Cache; |
|
4 | - |
|
5 | - \App::uses('CakeEvent', 'Event'); |
|
6 | - \App::uses('CakeEventListener', 'Event'); |
|
7 | - |
|
8 | - class CacheSupport extends \Object implements \CakeEventListener { |
|
9 | - |
|
10 | - protected $_Caches = []; |
|
11 | - |
|
12 | - protected $_buildInCaches = [ |
|
13 | - // php caches |
|
14 | - 'ApcCacheSupportCachelet', |
|
15 | - 'OpCacheSupportCachelet', |
|
16 | - // application caches |
|
17 | - 'EntriesCacheSupportCachelet', |
|
18 | - 'CakeCacheSupportCachelet', |
|
19 | - 'SaitoCacheSupportCachelet', |
|
20 | - ]; |
|
21 | - |
|
22 | - protected $_metaKeys = [ |
|
23 | - 'Thread' => ['EntriesCache', 'LineCache'] |
|
24 | - ]; |
|
25 | - |
|
26 | - public function __construct() { |
|
27 | - foreach ($this->_buildInCaches as $_name) { |
|
28 | - $name = 'Saito\Cache\\' . $_name; |
|
29 | - $this->add(new $name); |
|
30 | - } |
|
31 | - \CakeEventManager::instance()->attach($this); |
|
32 | - } |
|
33 | - |
|
34 | - public function implementedEvents() { |
|
35 | - return ['Cmd.Cache.clear' => 'onClear']; |
|
36 | - } |
|
37 | - |
|
38 | - /** |
|
39 | - * Clears out cache by name in $event['cache']; |
|
40 | - * |
|
41 | - * @param $event |
|
42 | - */ |
|
43 | - public function onClear($event) { |
|
44 | - $cache = $event->data['cache']; |
|
45 | - $id = isset($event->data['id']) ? $event->data['id'] : null; |
|
46 | - $this->clear($cache, $id); |
|
47 | - } |
|
48 | - |
|
49 | - /** |
|
50 | - * @param mixed $cache cache to clear |
|
51 | - * null: all |
|
52 | - * string: name of specific cache |
|
53 | - * array: multiple name strings |
|
54 | - * @param null $id |
|
55 | - */ |
|
56 | - public function clear($cache = null, $id = null) { |
|
57 | - if (is_string($cache) && isset($this->_metaKeys[$cache])) { |
|
58 | - $cache = $this->_metaKeys[$cache]; |
|
59 | - } |
|
60 | - if (is_array($cache)) { |
|
61 | - foreach ($cache as $_c) { |
|
62 | - $this->clear($_c, $id); |
|
63 | - } |
|
64 | - return; |
|
65 | - } |
|
66 | - if ($cache === null) { |
|
67 | - foreach ($this->_Caches as $_Cache) { |
|
68 | - $_Cache->clear(); |
|
69 | - } |
|
70 | - } else { |
|
71 | - if (isset($this->_Caches[$cache])) { |
|
72 | - $this->_Caches[$cache]->clear($id); |
|
73 | - } |
|
74 | - } |
|
75 | - } |
|
76 | - |
|
77 | - public function add(CacheSupportCacheletInterface $cache, $id = null) { |
|
78 | - if ($id === null) { |
|
79 | - $id = $cache->getId(); |
|
80 | - } |
|
81 | - if (!isset($this->_Caches[$id])) { |
|
82 | - $this->_Caches[$id] = $cache; |
|
83 | - } |
|
84 | - } |
|
85 | - |
|
86 | - } |
|
87 | - |
|
88 | - interface CacheSupportCacheletInterface { |
|
89 | - |
|
90 | - public function clear($id = null); |
|
91 | - |
|
92 | - public function getId(); |
|
93 | - |
|
94 | - } |
|
95 | - |
|
96 | - class SaitoCacheSupportCachelet extends CacheSupportCachelet { |
|
97 | - |
|
98 | - public function clear($id = null) { |
|
99 | - \Cache::clear(false, 'default'); |
|
100 | - \Cache::clear(false, 'short'); |
|
101 | - } |
|
102 | - |
|
103 | - } |
|
104 | - |
|
105 | - class ApcCacheSupportCachelet extends CacheSupportCachelet { |
|
106 | - |
|
107 | - public function clear($id = null) { |
|
108 | - if (function_exists('apc_store')) { |
|
109 | - apc_clear_cache(); |
|
110 | - apc_clear_cache('user'); |
|
111 | - apc_clear_cache('opcode'); |
|
112 | - } |
|
113 | - } |
|
114 | - |
|
115 | - } |
|
116 | - |
|
117 | - class OpCacheSupportCachelet extends CacheSupportCachelet { |
|
118 | - |
|
119 | - public function clear($id = null) { |
|
120 | - if (function_exists('opcache_reset')) { |
|
121 | - opcache_reset(); |
|
122 | - } |
|
123 | - } |
|
124 | - |
|
125 | - } |
|
126 | - |
|
127 | - class CakeCacheSupportCachelet extends CacheSupportCachelet { |
|
128 | - |
|
129 | - protected $_title = 'Cake'; |
|
130 | - |
|
131 | - public function clear($id = null) { |
|
132 | - \Cache::clearGroup('persistent'); |
|
133 | - \Cache::clearGroup('models'); |
|
134 | - \Cache::clearGroup('views'); |
|
135 | - } |
|
136 | - |
|
137 | - } |
|
138 | - |
|
139 | - class EntriesCacheSupportCachelet extends CacheSupportCachelet implements \CakeEventListener { |
|
140 | - |
|
141 | - // only rename if you rename event cmds triggering this cache |
|
142 | - protected $_title = 'EntriesCache'; |
|
143 | - |
|
144 | - protected $_CacheTree; |
|
145 | - |
|
146 | - public function __construct() { |
|
147 | - \CakeEventManager::instance()->attach($this); |
|
148 | - } |
|
149 | - |
|
150 | - public function implementedEvents() { |
|
151 | - return [ |
|
152 | - 'Model.Thread.change' => 'onThreadChanged', |
|
153 | - 'Model.Entry.replyToEntry' => 'onEntryChanged', |
|
154 | - 'Model.Entry.update' => 'onEntryChanged' |
|
155 | - ]; |
|
156 | - } |
|
157 | - |
|
158 | - public function onThreadChanged($event) { |
|
159 | - $this->clear(); |
|
160 | - } |
|
3 | + namespace Saito\Cache; |
|
4 | + |
|
5 | + \App::uses('CakeEvent', 'Event'); |
|
6 | + \App::uses('CakeEventListener', 'Event'); |
|
7 | + |
|
8 | + class CacheSupport extends \Object implements \CakeEventListener { |
|
9 | + |
|
10 | + protected $_Caches = []; |
|
11 | + |
|
12 | + protected $_buildInCaches = [ |
|
13 | + // php caches |
|
14 | + 'ApcCacheSupportCachelet', |
|
15 | + 'OpCacheSupportCachelet', |
|
16 | + // application caches |
|
17 | + 'EntriesCacheSupportCachelet', |
|
18 | + 'CakeCacheSupportCachelet', |
|
19 | + 'SaitoCacheSupportCachelet', |
|
20 | + ]; |
|
21 | + |
|
22 | + protected $_metaKeys = [ |
|
23 | + 'Thread' => ['EntriesCache', 'LineCache'] |
|
24 | + ]; |
|
25 | + |
|
26 | + public function __construct() { |
|
27 | + foreach ($this->_buildInCaches as $_name) { |
|
28 | + $name = 'Saito\Cache\\' . $_name; |
|
29 | + $this->add(new $name); |
|
30 | + } |
|
31 | + \CakeEventManager::instance()->attach($this); |
|
32 | + } |
|
33 | + |
|
34 | + public function implementedEvents() { |
|
35 | + return ['Cmd.Cache.clear' => 'onClear']; |
|
36 | + } |
|
37 | + |
|
38 | + /** |
|
39 | + * Clears out cache by name in $event['cache']; |
|
40 | + * |
|
41 | + * @param $event |
|
42 | + */ |
|
43 | + public function onClear($event) { |
|
44 | + $cache = $event->data['cache']; |
|
45 | + $id = isset($event->data['id']) ? $event->data['id'] : null; |
|
46 | + $this->clear($cache, $id); |
|
47 | + } |
|
48 | + |
|
49 | + /** |
|
50 | + * @param mixed $cache cache to clear |
|
51 | + * null: all |
|
52 | + * string: name of specific cache |
|
53 | + * array: multiple name strings |
|
54 | + * @param null $id |
|
55 | + */ |
|
56 | + public function clear($cache = null, $id = null) { |
|
57 | + if (is_string($cache) && isset($this->_metaKeys[$cache])) { |
|
58 | + $cache = $this->_metaKeys[$cache]; |
|
59 | + } |
|
60 | + if (is_array($cache)) { |
|
61 | + foreach ($cache as $_c) { |
|
62 | + $this->clear($_c, $id); |
|
63 | + } |
|
64 | + return; |
|
65 | + } |
|
66 | + if ($cache === null) { |
|
67 | + foreach ($this->_Caches as $_Cache) { |
|
68 | + $_Cache->clear(); |
|
69 | + } |
|
70 | + } else { |
|
71 | + if (isset($this->_Caches[$cache])) { |
|
72 | + $this->_Caches[$cache]->clear($id); |
|
73 | + } |
|
74 | + } |
|
75 | + } |
|
76 | + |
|
77 | + public function add(CacheSupportCacheletInterface $cache, $id = null) { |
|
78 | + if ($id === null) { |
|
79 | + $id = $cache->getId(); |
|
80 | + } |
|
81 | + if (!isset($this->_Caches[$id])) { |
|
82 | + $this->_Caches[$id] = $cache; |
|
83 | + } |
|
84 | + } |
|
85 | + |
|
86 | + } |
|
87 | + |
|
88 | + interface CacheSupportCacheletInterface { |
|
89 | + |
|
90 | + public function clear($id = null); |
|
91 | + |
|
92 | + public function getId(); |
|
93 | + |
|
94 | + } |
|
95 | + |
|
96 | + class SaitoCacheSupportCachelet extends CacheSupportCachelet { |
|
97 | + |
|
98 | + public function clear($id = null) { |
|
99 | + \Cache::clear(false, 'default'); |
|
100 | + \Cache::clear(false, 'short'); |
|
101 | + } |
|
102 | + |
|
103 | + } |
|
104 | + |
|
105 | + class ApcCacheSupportCachelet extends CacheSupportCachelet { |
|
106 | + |
|
107 | + public function clear($id = null) { |
|
108 | + if (function_exists('apc_store')) { |
|
109 | + apc_clear_cache(); |
|
110 | + apc_clear_cache('user'); |
|
111 | + apc_clear_cache('opcode'); |
|
112 | + } |
|
113 | + } |
|
114 | + |
|
115 | + } |
|
116 | + |
|
117 | + class OpCacheSupportCachelet extends CacheSupportCachelet { |
|
118 | + |
|
119 | + public function clear($id = null) { |
|
120 | + if (function_exists('opcache_reset')) { |
|
121 | + opcache_reset(); |
|
122 | + } |
|
123 | + } |
|
124 | + |
|
125 | + } |
|
126 | + |
|
127 | + class CakeCacheSupportCachelet extends CacheSupportCachelet { |
|
128 | + |
|
129 | + protected $_title = 'Cake'; |
|
130 | + |
|
131 | + public function clear($id = null) { |
|
132 | + \Cache::clearGroup('persistent'); |
|
133 | + \Cache::clearGroup('models'); |
|
134 | + \Cache::clearGroup('views'); |
|
135 | + } |
|
136 | + |
|
137 | + } |
|
138 | + |
|
139 | + class EntriesCacheSupportCachelet extends CacheSupportCachelet implements \CakeEventListener { |
|
140 | + |
|
141 | + // only rename if you rename event cmds triggering this cache |
|
142 | + protected $_title = 'EntriesCache'; |
|
143 | + |
|
144 | + protected $_CacheTree; |
|
145 | + |
|
146 | + public function __construct() { |
|
147 | + \CakeEventManager::instance()->attach($this); |
|
148 | + } |
|
149 | + |
|
150 | + public function implementedEvents() { |
|
151 | + return [ |
|
152 | + 'Model.Thread.change' => 'onThreadChanged', |
|
153 | + 'Model.Entry.replyToEntry' => 'onEntryChanged', |
|
154 | + 'Model.Entry.update' => 'onEntryChanged' |
|
155 | + ]; |
|
156 | + } |
|
157 | + |
|
158 | + public function onThreadChanged($event) { |
|
159 | + $this->clear(); |
|
160 | + } |
|
161 | 161 | |
162 | - /** |
|
163 | - * @param $event |
|
164 | - * @throws InvalidArgumentException |
|
165 | - */ |
|
166 | - public function onEntryChanged($event) { |
|
167 | - $this->clear(); |
|
168 | - } |
|
162 | + /** |
|
163 | + * @param $event |
|
164 | + * @throws InvalidArgumentException |
|
165 | + */ |
|
166 | + public function onEntryChanged($event) { |
|
167 | + $this->clear(); |
|
168 | + } |
|
169 | 169 | |
170 | - public function clear($id = null) { |
|
171 | - \Cache::clearGroup('entries', 'entries'); |
|
172 | - } |
|
170 | + public function clear($id = null) { |
|
171 | + \Cache::clearGroup('entries', 'entries'); |
|
172 | + } |
|
173 | 173 | |
174 | - } |
|
174 | + } |
@@ -20,7 +20,7 @@ discard block |
||
20 | 20 | if ($language === null) { |
21 | 21 | $language = static::$_lang; |
22 | 22 | } |
23 | - $_method = '_properize' . ucfirst($language); |
|
23 | + $_method = '_properize'.ucfirst($language); |
|
24 | 24 | if (!method_exists(get_class(), $_method)) { |
25 | 25 | throw new \InvalidArgumentException("Properize: unknown language '$language'"); |
26 | 26 | } |
@@ -33,7 +33,7 @@ discard block |
||
33 | 33 | if (isset($apo[mb_substr($string, -1)])) { |
34 | 34 | $suffix = '’'; |
35 | 35 | } |
36 | - return $string . $suffix; |
|
36 | + return $string.$suffix; |
|
37 | 37 | } |
38 | 38 | |
39 | 39 | protected static function _properizeDeu($string) { |
@@ -48,7 +48,7 @@ discard block |
||
48 | 48 | $suffix = '’'; |
49 | 49 | } |
50 | 50 | |
51 | - return $string . $suffix; |
|
51 | + return $string.$suffix; |
|
52 | 52 | } |
53 | 53 | |
54 | 54 | } |
55 | 55 | \ No newline at end of file |
@@ -1,54 +1,54 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\String; |
|
4 | - |
|
5 | - class Properize { |
|
6 | - |
|
7 | - static protected $_lang; |
|
8 | - |
|
9 | - public static function setLanguage($lang) { |
|
10 | - static::$_lang = $lang; |
|
11 | - } |
|
12 | - |
|
13 | - /** |
|
14 | - * @param $string word to properize |
|
15 | - * @param string $language |
|
16 | - * @throws \InvalidArgumentException |
|
17 | - * @return mixed $string |
|
18 | - */ |
|
19 | - public static function prop($string, $language = null) { |
|
20 | - if ($language === null) { |
|
21 | - $language = static::$_lang; |
|
22 | - } |
|
23 | - $_method = '_properize' . ucfirst($language); |
|
24 | - if (!method_exists(get_class(), $_method)) { |
|
25 | - throw new \InvalidArgumentException("Properize: unknown language '$language'"); |
|
26 | - } |
|
27 | - return static::$_method($string); |
|
28 | - } |
|
29 | - |
|
30 | - protected static function _properizeEng($string) { |
|
31 | - $suffix = '’s'; |
|
32 | - $apo = ['S' => 1, 's' => 1]; |
|
33 | - if (isset($apo[mb_substr($string, -1)])) { |
|
34 | - $suffix = '’'; |
|
35 | - } |
|
36 | - return $string . $suffix; |
|
37 | - } |
|
38 | - |
|
39 | - protected static function _properizeDeu($string) { |
|
40 | - $suffix = 's'; |
|
41 | - $apo = ['S' => 1, 's' => 1, 'ß' => 1, 'x' => 1, 'z' => 1]; |
|
42 | - |
|
43 | - if (isset($apo[mb_substr($string, -1)])) { |
|
44 | - // Hans’ Tante |
|
45 | - $suffix = '’'; |
|
46 | - } elseif ('ce' === (mb_substr($string, -2))) { |
|
47 | - // Alice’ Tante |
|
48 | - $suffix = '’'; |
|
49 | - } |
|
50 | - |
|
51 | - return $string . $suffix; |
|
52 | - } |
|
53 | - |
|
54 | - } |
|
55 | 3 | \ No newline at end of file |
4 | + namespace Saito\String; |
|
5 | + |
|
6 | + class Properize { |
|
7 | + |
|
8 | + static protected $_lang; |
|
9 | + |
|
10 | + public static function setLanguage($lang) { |
|
11 | + static::$_lang = $lang; |
|
12 | + } |
|
13 | + |
|
14 | + /** |
|
15 | + * @param $string word to properize |
|
16 | + * @param string $language |
|
17 | + * @throws \InvalidArgumentException |
|
18 | + * @return mixed $string |
|
19 | + */ |
|
20 | + public static function prop($string, $language = null) { |
|
21 | + if ($language === null) { |
|
22 | + $language = static::$_lang; |
|
23 | + } |
|
24 | + $_method = '_properize' . ucfirst($language); |
|
25 | + if (!method_exists(get_class(), $_method)) { |
|
26 | + throw new \InvalidArgumentException("Properize: unknown language '$language'"); |
|
27 | + } |
|
28 | + return static::$_method($string); |
|
29 | + } |
|
30 | + |
|
31 | + protected static function _properizeEng($string) { |
|
32 | + $suffix = '’s'; |
|
33 | + $apo = ['S' => 1, 's' => 1]; |
|
34 | + if (isset($apo[mb_substr($string, -1)])) { |
|
35 | + $suffix = '’'; |
|
36 | + } |
|
37 | + return $string . $suffix; |
|
38 | + } |
|
39 | + |
|
40 | + protected static function _properizeDeu($string) { |
|
41 | + $suffix = 's'; |
|
42 | + $apo = ['S' => 1, 's' => 1, 'ß' => 1, 'x' => 1, 'z' => 1]; |
|
43 | + |
|
44 | + if (isset($apo[mb_substr($string, -1)])) { |
|
45 | + // Hans’ Tante |
|
46 | + $suffix = '’'; |
|
47 | + } elseif ('ce' === (mb_substr($string, -2))) { |
|
48 | + // Alice’ Tante |
|
49 | + $suffix = '’'; |
|
50 | + } |
|
51 | + |
|
52 | + return $string . $suffix; |
|
53 | + } |
|
54 | + |
|
55 | + } |
|
56 | 56 | \ No newline at end of file |
@@ -35,7 +35,7 @@ discard block |
||
35 | 35 | } |
36 | 36 | |
37 | 37 | public function getOmittedWords() { |
38 | - $filter = function ($word) { |
|
38 | + $filter = function($word) { |
|
39 | 39 | return mb_strlen($word) < $this->_length; |
40 | 40 | }; |
41 | 41 | $string = preg_replace('/(".*")/', '', $this->_string); |
@@ -74,7 +74,7 @@ discard block |
||
74 | 74 | if (mb_strpos($word, '-') === false) { |
75 | 75 | continue; |
76 | 76 | } |
77 | - $string = str_replace($word, '"' . $word . '"', $string); |
|
77 | + $string = str_replace($word, '"'.$word.'"', $string); |
|
78 | 78 | } |
79 | 79 | return $string; |
80 | 80 | } |
@@ -1,82 +1,82 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito; |
|
3 | + namespace Saito; |
|
4 | 4 | |
5 | - class SimpleSearchString { |
|
5 | + class SimpleSearchString { |
|
6 | 6 | |
7 | - protected $_length = 4; |
|
7 | + protected $_length = 4; |
|
8 | 8 | |
9 | - protected $_operators = '+-'; |
|
9 | + protected $_operators = '+-'; |
|
10 | 10 | |
11 | - protected $_string; |
|
11 | + protected $_string; |
|
12 | 12 | |
13 | - public function __construct($string, $length = null) { |
|
14 | - $this->_string = $string; |
|
15 | - if ($length) { |
|
16 | - $this->_length = $length; |
|
17 | - } |
|
18 | - } |
|
13 | + public function __construct($string, $length = null) { |
|
14 | + $this->_string = $string; |
|
15 | + if ($length) { |
|
16 | + $this->_length = $length; |
|
17 | + } |
|
18 | + } |
|
19 | 19 | |
20 | - /** |
|
21 | - * @param mixed $string |
|
22 | - */ |
|
23 | - public function setString($string) { |
|
24 | - $this->_string = $string; |
|
25 | - } |
|
20 | + /** |
|
21 | + * @param mixed $string |
|
22 | + */ |
|
23 | + public function setString($string) { |
|
24 | + $this->_string = $string; |
|
25 | + } |
|
26 | 26 | |
27 | - /** |
|
28 | - * Checks if search words have minimal word length |
|
29 | - */ |
|
30 | - public function validateLength() { |
|
31 | - if (empty($this->_string)) { |
|
32 | - return false; |
|
33 | - } |
|
34 | - return strlen($this->getOmittedWords()) === 0; |
|
35 | - } |
|
27 | + /** |
|
28 | + * Checks if search words have minimal word length |
|
29 | + */ |
|
30 | + public function validateLength() { |
|
31 | + if (empty($this->_string)) { |
|
32 | + return false; |
|
33 | + } |
|
34 | + return strlen($this->getOmittedWords()) === 0; |
|
35 | + } |
|
36 | 36 | |
37 | - public function getOmittedWords() { |
|
38 | - $filter = function ($word) { |
|
39 | - return mb_strlen($word) < $this->_length; |
|
40 | - }; |
|
41 | - $string = preg_replace('/(".*")/', '', $this->_string); |
|
42 | - $words = $this->_split($string); |
|
43 | - $result = array_filter($words, $filter); |
|
44 | - return implode(' ', $result); |
|
45 | - } |
|
37 | + public function getOmittedWords() { |
|
38 | + $filter = function ($word) { |
|
39 | + return mb_strlen($word) < $this->_length; |
|
40 | + }; |
|
41 | + $string = preg_replace('/(".*")/', '', $this->_string); |
|
42 | + $words = $this->_split($string); |
|
43 | + $result = array_filter($words, $filter); |
|
44 | + return implode(' ', $result); |
|
45 | + } |
|
46 | 46 | |
47 | - protected function _split($string) { |
|
48 | - return preg_split("/(^|\s+)[{$this->_operators}]?/", $string, -1, |
|
49 | - PREG_SPLIT_NO_EMPTY); |
|
50 | - } |
|
47 | + protected function _split($string) { |
|
48 | + return preg_split("/(^|\s+)[{$this->_operators}]?/", $string, -1, |
|
49 | + PREG_SPLIT_NO_EMPTY); |
|
50 | + } |
|
51 | 51 | |
52 | - /** |
|
53 | - * replaces whitespace with '+' |
|
54 | - * |
|
55 | - * whitespace should imply AND (not OR) |
|
56 | - * |
|
57 | - * @return string |
|
58 | - */ |
|
59 | - public function replaceOperators() { |
|
60 | - $string = $this->_fulltextHyphenFix($this->_string); |
|
61 | - return ltrim(preg_replace('/(^|\s)(?![-+><])/i', ' +', $string)); |
|
62 | - } |
|
52 | + /** |
|
53 | + * replaces whitespace with '+' |
|
54 | + * |
|
55 | + * whitespace should imply AND (not OR) |
|
56 | + * |
|
57 | + * @return string |
|
58 | + */ |
|
59 | + public function replaceOperators() { |
|
60 | + $string = $this->_fulltextHyphenFix($this->_string); |
|
61 | + return ltrim(preg_replace('/(^|\s)(?![-+><])/i', ' +', $string)); |
|
62 | + } |
|
63 | 63 | |
64 | - /** |
|
65 | - * @see: http://bugs.mysql.com/bug.php?id=2095 |
|
66 | - */ |
|
67 | - protected function _fulltextHyphenFix($string) { |
|
68 | - $words = $this->_split($string); |
|
69 | - foreach ($words as $word) { |
|
70 | - $first = mb_substr($word, 0, 1); |
|
71 | - if ($first === '"') { |
|
72 | - continue; |
|
73 | - } |
|
74 | - if (mb_strpos($word, '-') === false) { |
|
75 | - continue; |
|
76 | - } |
|
77 | - $string = str_replace($word, '"' . $word . '"', $string); |
|
78 | - } |
|
79 | - return $string; |
|
80 | - } |
|
64 | + /** |
|
65 | + * @see: http://bugs.mysql.com/bug.php?id=2095 |
|
66 | + */ |
|
67 | + protected function _fulltextHyphenFix($string) { |
|
68 | + $words = $this->_split($string); |
|
69 | + foreach ($words as $word) { |
|
70 | + $first = mb_substr($word, 0, 1); |
|
71 | + if ($first === '"') { |
|
72 | + continue; |
|
73 | + } |
|
74 | + if (mb_strpos($word, '-') === false) { |
|
75 | + continue; |
|
76 | + } |
|
77 | + $string = str_replace($word, '"' . $word . '"', $string); |
|
78 | + } |
|
79 | + return $string; |
|
80 | + } |
|
81 | 81 | |
82 | - } |
|
82 | + } |
@@ -12,10 +12,10 @@ discard block |
||
12 | 12 | public function getBadges(\Saito\Posting\PostingInterface $entry) { |
13 | 13 | $out = ''; |
14 | 14 | if ($entry->isPinned()) { |
15 | - $out .= '<i class="fa fa-thumb-tack" title="' . __('fixed') . '"></i> '; |
|
15 | + $out .= '<i class="fa fa-thumb-tack" title="'.__('fixed').'"></i> '; |
|
16 | 16 | } |
17 | 17 | // anchor for inserting solve-icon via FE-JS |
18 | - $out .= '<span class="solves ' . $entry->get('id') . '">'; |
|
18 | + $out .= '<span class="solves '.$entry->get('id').'">'; |
|
19 | 19 | if ($entry->get('solves')) { |
20 | 20 | $out .= $this->solvedBadge(); |
21 | 21 | } |
@@ -36,8 +36,8 @@ discard block |
||
36 | 36 | } |
37 | 37 | |
38 | 38 | public function solvedBadge() { |
39 | - return '<i class="fa fa-badge-solves solves-isSolved" title="' . |
|
40 | - __('Helpful entry') . '"></i>'; |
|
39 | + return '<i class="fa fa-badge-solves solves-isSolved" title="'. |
|
40 | + __('Helpful entry').'"></i>'; |
|
41 | 41 | } |
42 | 42 | |
43 | 43 | /** |
@@ -49,7 +49,7 @@ discard block |
||
49 | 49 | * @return string |
50 | 50 | */ |
51 | 51 | public function getSubject(\Saito\Posting\Posting $posting) { |
52 | - return \h($posting->get('subject')) . ($posting->isNt() ? ' n/t' : ''); |
|
52 | + return \h($posting->get('subject')).($posting->isNt() ? ' n/t' : ''); |
|
53 | 53 | } |
54 | 54 | |
55 | 55 | } |
56 | 56 | \ No newline at end of file |
@@ -1,55 +1,55 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\Posting\Renderer; |
|
4 | - |
|
5 | - \App::uses('SaitoEventManager', 'Lib/Saito/Event'); |
|
6 | - |
|
7 | - /** |
|
8 | - * Helper methods for rendering postings |
|
9 | - */ |
|
10 | - trait HelperTrait { |
|
11 | - |
|
12 | - public function getBadges(\Saito\Posting\PostingInterface $entry) { |
|
13 | - $out = ''; |
|
14 | - if ($entry->isPinned()) { |
|
15 | - $out .= '<i class="fa fa-thumb-tack" title="' . __('fixed') . '"></i> '; |
|
16 | - } |
|
17 | - // anchor for inserting solve-icon via FE-JS |
|
18 | - $out .= '<span class="solves ' . $entry->get('id') . '">'; |
|
19 | - if ($entry->get('solves')) { |
|
20 | - $out .= $this->solvedBadge(); |
|
21 | - } |
|
22 | - $out .= '</span>'; |
|
23 | - |
|
24 | - if (!isset($this->_SEM)) { |
|
25 | - $this->_SEM = \SaitoEventManager::getInstance(); |
|
26 | - } |
|
27 | - $additionalBadges = $this->_SEM->dispatch( |
|
28 | - 'Request.Saito.View.Posting.badges', |
|
29 | - ['posting' => $entry->getRaw()] |
|
30 | - ); |
|
31 | - if ($additionalBadges) { |
|
32 | - $out .= implode('', $additionalBadges); |
|
33 | - } |
|
34 | - |
|
35 | - return $out; |
|
36 | - } |
|
37 | - |
|
38 | - public function solvedBadge() { |
|
39 | - return '<i class="fa fa-badge-solves solves-isSolved" title="' . |
|
40 | - __('Helpful entry') . '"></i>'; |
|
41 | - } |
|
42 | - |
|
43 | - /** |
|
44 | - * |
|
45 | - * This function may be called serveral hundred times on the front page. |
|
46 | - * Don't make ist slow, benchmark! |
|
47 | - * |
|
48 | - * @param $posting |
|
49 | - * @return string |
|
50 | - */ |
|
51 | - public function getSubject(\Saito\Posting\Posting $posting) { |
|
52 | - return \h($posting->get('subject')) . ($posting->isNt() ? ' n/t' : ''); |
|
53 | - } |
|
54 | - |
|
55 | - } |
|
56 | 3 | \ No newline at end of file |
4 | + namespace Saito\Posting\Renderer; |
|
5 | + |
|
6 | + \App::uses('SaitoEventManager', 'Lib/Saito/Event'); |
|
7 | + |
|
8 | + /** |
|
9 | + * Helper methods for rendering postings |
|
10 | + */ |
|
11 | + trait HelperTrait { |
|
12 | + |
|
13 | + public function getBadges(\Saito\Posting\PostingInterface $entry) { |
|
14 | + $out = ''; |
|
15 | + if ($entry->isPinned()) { |
|
16 | + $out .= '<i class="fa fa-thumb-tack" title="' . __('fixed') . '"></i> '; |
|
17 | + } |
|
18 | + // anchor for inserting solve-icon via FE-JS |
|
19 | + $out .= '<span class="solves ' . $entry->get('id') . '">'; |
|
20 | + if ($entry->get('solves')) { |
|
21 | + $out .= $this->solvedBadge(); |
|
22 | + } |
|
23 | + $out .= '</span>'; |
|
24 | + |
|
25 | + if (!isset($this->_SEM)) { |
|
26 | + $this->_SEM = \SaitoEventManager::getInstance(); |
|
27 | + } |
|
28 | + $additionalBadges = $this->_SEM->dispatch( |
|
29 | + 'Request.Saito.View.Posting.badges', |
|
30 | + ['posting' => $entry->getRaw()] |
|
31 | + ); |
|
32 | + if ($additionalBadges) { |
|
33 | + $out .= implode('', $additionalBadges); |
|
34 | + } |
|
35 | + |
|
36 | + return $out; |
|
37 | + } |
|
38 | + |
|
39 | + public function solvedBadge() { |
|
40 | + return '<i class="fa fa-badge-solves solves-isSolved" title="' . |
|
41 | + __('Helpful entry') . '"></i>'; |
|
42 | + } |
|
43 | + |
|
44 | + /** |
|
45 | + * |
|
46 | + * This function may be called serveral hundred times on the front page. |
|
47 | + * Don't make ist slow, benchmark! |
|
48 | + * |
|
49 | + * @param $posting |
|
50 | + * @return string |
|
51 | + */ |
|
52 | + public function getSubject(\Saito\Posting\Posting $posting) { |
|
53 | + return \h($posting->get('subject')) . ($posting->isNt() ? ' n/t' : ''); |
|
54 | + } |
|
55 | + |
|
56 | + } |
|
57 | 57 | \ No newline at end of file |
@@ -18,12 +18,12 @@ |
||
18 | 18 | |
19 | 19 | public function __construct(\Saito\User\ForumsUserInterface $CurrentUser, $rawData, array $options = [], $tree = null) { |
20 | 20 | $this->_rawData = $rawData; |
21 | - $this->_rawData[self::ALIAS]['id'] = (int)$this->_rawData[self::ALIAS]['id']; |
|
21 | + $this->_rawData[self::ALIAS]['id'] = (int) $this->_rawData[self::ALIAS]['id']; |
|
22 | 22 | if (isset($this->_rawData[self::ALIAS]['pid'])) { |
23 | - $this->_rawData[self::ALIAS]['pid'] = (int)$this->_rawData[self::ALIAS]['pid']; |
|
23 | + $this->_rawData[self::ALIAS]['pid'] = (int) $this->_rawData[self::ALIAS]['pid']; |
|
24 | 24 | } |
25 | 25 | if (isset($this->_rawData[self::ALIAS]['tid'])) { |
26 | - $this->_rawData[self::ALIAS]['tid'] = (int)$this->_rawData[self::ALIAS]['tid']; |
|
26 | + $this->_rawData[self::ALIAS]['tid'] = (int) $this->_rawData[self::ALIAS]['tid']; |
|
27 | 27 | } |
28 | 28 | |
29 | 29 | $this->setCurrentUser($CurrentUser); |
@@ -1,126 +1,126 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\Posting; |
|
4 | - |
|
5 | - class Posting implements PostingInterface { |
|
6 | - |
|
7 | - use Decorator\UserPostingTrait; |
|
8 | - |
|
9 | - const ALIAS = 'Entry'; |
|
10 | - |
|
11 | - protected $_children = []; |
|
12 | - |
|
13 | - protected $_level; |
|
14 | - |
|
15 | - protected $_rawData; |
|
16 | - |
|
17 | - protected $_Thread; |
|
18 | - |
|
19 | - public function __construct(\Saito\User\ForumsUserInterface $CurrentUser, $rawData, array $options = [], $tree = null) { |
|
20 | - $this->_rawData = $rawData; |
|
21 | - $this->_rawData[self::ALIAS]['id'] = (int)$this->_rawData[self::ALIAS]['id']; |
|
22 | - if (isset($this->_rawData[self::ALIAS]['pid'])) { |
|
23 | - $this->_rawData[self::ALIAS]['pid'] = (int)$this->_rawData[self::ALIAS]['pid']; |
|
24 | - } |
|
25 | - if (isset($this->_rawData[self::ALIAS]['tid'])) { |
|
26 | - $this->_rawData[self::ALIAS]['tid'] = (int)$this->_rawData[self::ALIAS]['tid']; |
|
27 | - } |
|
28 | - |
|
29 | - $this->setCurrentUser($CurrentUser); |
|
30 | - |
|
31 | - $options += ['level' => 0]; |
|
32 | - $this->_level = $options['level']; |
|
33 | - |
|
34 | - if (!$tree) { |
|
35 | - $tree = new \Saito\Thread\Thread; |
|
36 | - } |
|
37 | - $this->_Thread = $tree; |
|
38 | - $this->_Thread->add($this); |
|
39 | - |
|
40 | - $this->_attachChildren(); |
|
41 | - return $this; |
|
42 | - } |
|
43 | - |
|
44 | - /** |
|
45 | - * @param $var |
|
46 | - * @return mixed |
|
47 | - * @throws \InvalidArgumentException |
|
48 | - */ |
|
49 | - public function get($var) { |
|
50 | - switch ($var) { |
|
51 | - case (isset($this->_rawData[self::ALIAS][$var])): |
|
52 | - return $this->_rawData[self::ALIAS][$var]; |
|
53 | - case (isset($this->_rawData[$var])): |
|
54 | - return $this->_rawData[$var]; |
|
55 | - // if key is set but null |
|
56 | - case (array_key_exists($var, $this->_rawData[self::ALIAS])): |
|
57 | - return $this->_rawData[self::ALIAS][$var]; |
|
58 | - default: |
|
59 | - throw new \InvalidArgumentException("Attribute '$var' not found in class Posting."); |
|
60 | - } |
|
61 | - } |
|
62 | - |
|
63 | - public function getLevel() { |
|
64 | - return $this->_level; |
|
65 | - } |
|
66 | - |
|
67 | - public function getChildren() { |
|
68 | - return $this->_children; |
|
69 | - } |
|
70 | - |
|
71 | - public function getRaw() { |
|
72 | - return $this->_rawData; |
|
73 | - } |
|
74 | - |
|
75 | - public function getThread() { |
|
76 | - return $this->_Thread; |
|
77 | - } |
|
78 | - |
|
79 | - public function hasAnswers() { |
|
80 | - return count($this->_children) > 0; |
|
81 | - } |
|
82 | - |
|
83 | - public function isLocked() { |
|
84 | - return $this->get('locked') != false; |
|
85 | - } |
|
86 | - |
|
87 | - /** |
|
88 | - * checks if entry is n/t |
|
89 | - * |
|
90 | - * @return bool |
|
91 | - */ |
|
92 | - public function isNt() { |
|
93 | - return empty($this->_rawData[self::ALIAS]['text']); |
|
94 | - } |
|
95 | - |
|
96 | - public function isPinned() { |
|
97 | - return $this->_rawData[self::ALIAS]['fixed'] == true; |
|
98 | - } |
|
99 | - |
|
100 | - public function isRoot() { |
|
101 | - return $this->_rawData[self::ALIAS]['pid'] === 0; |
|
102 | - } |
|
103 | - |
|
104 | - public function addDecorator($fct) { |
|
105 | - foreach ($this->_children as $key => $child) { |
|
106 | - $newChild = $fct($child); |
|
107 | - $newChild->addDecorator($fct); |
|
108 | - $this->_children[$key] = $newChild; |
|
109 | - } |
|
110 | - $new = $fct($this); |
|
111 | - // replace decorated object in Thread collection |
|
112 | - $this->_Thread->add($new); |
|
113 | - return $new; |
|
114 | - } |
|
115 | - |
|
116 | - protected function _attachChildren() { |
|
117 | - if (isset($this->_rawData['_children'])) { |
|
118 | - foreach ($this->_rawData['_children'] as $child) { |
|
119 | - $this->_children[] = new Posting($this->getCurrentUser(), $child, ['level' => $this->_level + 1], $this->_Thread); |
|
120 | - } |
|
121 | - } |
|
122 | - unset($this->_rawData['_children']); |
|
123 | - } |
|
124 | - |
|
125 | - } |
|
3 | + namespace Saito\Posting; |
|
4 | + |
|
5 | + class Posting implements PostingInterface { |
|
6 | + |
|
7 | + use Decorator\UserPostingTrait; |
|
8 | + |
|
9 | + const ALIAS = 'Entry'; |
|
10 | + |
|
11 | + protected $_children = []; |
|
12 | + |
|
13 | + protected $_level; |
|
14 | + |
|
15 | + protected $_rawData; |
|
16 | + |
|
17 | + protected $_Thread; |
|
18 | + |
|
19 | + public function __construct(\Saito\User\ForumsUserInterface $CurrentUser, $rawData, array $options = [], $tree = null) { |
|
20 | + $this->_rawData = $rawData; |
|
21 | + $this->_rawData[self::ALIAS]['id'] = (int)$this->_rawData[self::ALIAS]['id']; |
|
22 | + if (isset($this->_rawData[self::ALIAS]['pid'])) { |
|
23 | + $this->_rawData[self::ALIAS]['pid'] = (int)$this->_rawData[self::ALIAS]['pid']; |
|
24 | + } |
|
25 | + if (isset($this->_rawData[self::ALIAS]['tid'])) { |
|
26 | + $this->_rawData[self::ALIAS]['tid'] = (int)$this->_rawData[self::ALIAS]['tid']; |
|
27 | + } |
|
28 | + |
|
29 | + $this->setCurrentUser($CurrentUser); |
|
30 | + |
|
31 | + $options += ['level' => 0]; |
|
32 | + $this->_level = $options['level']; |
|
33 | + |
|
34 | + if (!$tree) { |
|
35 | + $tree = new \Saito\Thread\Thread; |
|
36 | + } |
|
37 | + $this->_Thread = $tree; |
|
38 | + $this->_Thread->add($this); |
|
39 | + |
|
40 | + $this->_attachChildren(); |
|
41 | + return $this; |
|
42 | + } |
|
43 | + |
|
44 | + /** |
|
45 | + * @param $var |
|
46 | + * @return mixed |
|
47 | + * @throws \InvalidArgumentException |
|
48 | + */ |
|
49 | + public function get($var) { |
|
50 | + switch ($var) { |
|
51 | + case (isset($this->_rawData[self::ALIAS][$var])): |
|
52 | + return $this->_rawData[self::ALIAS][$var]; |
|
53 | + case (isset($this->_rawData[$var])): |
|
54 | + return $this->_rawData[$var]; |
|
55 | + // if key is set but null |
|
56 | + case (array_key_exists($var, $this->_rawData[self::ALIAS])): |
|
57 | + return $this->_rawData[self::ALIAS][$var]; |
|
58 | + default: |
|
59 | + throw new \InvalidArgumentException("Attribute '$var' not found in class Posting."); |
|
60 | + } |
|
61 | + } |
|
62 | + |
|
63 | + public function getLevel() { |
|
64 | + return $this->_level; |
|
65 | + } |
|
66 | + |
|
67 | + public function getChildren() { |
|
68 | + return $this->_children; |
|
69 | + } |
|
70 | + |
|
71 | + public function getRaw() { |
|
72 | + return $this->_rawData; |
|
73 | + } |
|
74 | + |
|
75 | + public function getThread() { |
|
76 | + return $this->_Thread; |
|
77 | + } |
|
78 | + |
|
79 | + public function hasAnswers() { |
|
80 | + return count($this->_children) > 0; |
|
81 | + } |
|
82 | + |
|
83 | + public function isLocked() { |
|
84 | + return $this->get('locked') != false; |
|
85 | + } |
|
86 | + |
|
87 | + /** |
|
88 | + * checks if entry is n/t |
|
89 | + * |
|
90 | + * @return bool |
|
91 | + */ |
|
92 | + public function isNt() { |
|
93 | + return empty($this->_rawData[self::ALIAS]['text']); |
|
94 | + } |
|
95 | + |
|
96 | + public function isPinned() { |
|
97 | + return $this->_rawData[self::ALIAS]['fixed'] == true; |
|
98 | + } |
|
99 | + |
|
100 | + public function isRoot() { |
|
101 | + return $this->_rawData[self::ALIAS]['pid'] === 0; |
|
102 | + } |
|
103 | + |
|
104 | + public function addDecorator($fct) { |
|
105 | + foreach ($this->_children as $key => $child) { |
|
106 | + $newChild = $fct($child); |
|
107 | + $newChild->addDecorator($fct); |
|
108 | + $this->_children[$key] = $newChild; |
|
109 | + } |
|
110 | + $new = $fct($this); |
|
111 | + // replace decorated object in Thread collection |
|
112 | + $this->_Thread->add($new); |
|
113 | + return $new; |
|
114 | + } |
|
115 | + |
|
116 | + protected function _attachChildren() { |
|
117 | + if (isset($this->_rawData['_children'])) { |
|
118 | + foreach ($this->_rawData['_children'] as $child) { |
|
119 | + $this->_children[] = new Posting($this->getCurrentUser(), $child, ['level' => $this->_level + 1], $this->_Thread); |
|
120 | + } |
|
121 | + } |
|
122 | + unset($this->_rawData['_children']); |
|
123 | + } |
|
124 | + |
|
125 | + } |
|
126 | 126 |
@@ -28,9 +28,9 @@ |
||
28 | 28 | } |
29 | 29 | |
30 | 30 | public function cakeEventPassThrough($event) { |
31 | - $data = ($event->data) ? : []; |
|
31 | + $data = ($event->data) ?: []; |
|
32 | 32 | $data += ['subject' => $event->subject]; |
33 | - $name = 'Event.Saito.' . $event->name(); |
|
33 | + $name = 'Event.Saito.'.$event->name(); |
|
34 | 34 | $this->dispatch($name, $data); |
35 | 35 | } |
36 | 36 |
@@ -1,89 +1,89 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - /** |
|
4 | - * Event-manager for Saito |
|
5 | - * |
|
6 | - * A thin event manager with maximum dispatch speed. It's called a |
|
7 | - * few hundred times on the front-page and gives roughly 3x over |
|
8 | - * the CakeEventManager in Cake 2. |
|
9 | - */ |
|
10 | - class SaitoEventManager implements CakeEventListener { |
|
3 | + /** |
|
4 | + * Event-manager for Saito |
|
5 | + * |
|
6 | + * A thin event manager with maximum dispatch speed. It's called a |
|
7 | + * few hundred times on the front-page and gives roughly 3x over |
|
8 | + * the CakeEventManager in Cake 2. |
|
9 | + */ |
|
10 | + class SaitoEventManager implements CakeEventListener { |
|
11 | 11 | |
12 | - protected static $_Instance; |
|
12 | + protected static $_Instance; |
|
13 | 13 | |
14 | - protected $_listeners = []; |
|
14 | + protected $_listeners = []; |
|
15 | 15 | |
16 | - public static function getInstance() { |
|
17 | - if (self::$_Instance === null) { |
|
18 | - self::$_Instance = new SaitoEventManager(); |
|
19 | - } |
|
20 | - return self::$_Instance; |
|
21 | - } |
|
16 | + public static function getInstance() { |
|
17 | + if (self::$_Instance === null) { |
|
18 | + self::$_Instance = new SaitoEventManager(); |
|
19 | + } |
|
20 | + return self::$_Instance; |
|
21 | + } |
|
22 | 22 | |
23 | - public function implementedEvents() { |
|
24 | - return [ |
|
25 | - 'Controller.initialize' => 'cakeEventPassThrough', |
|
26 | - 'View.beforeRender' => 'cakeEventPassThrough' |
|
27 | - ]; |
|
28 | - } |
|
23 | + public function implementedEvents() { |
|
24 | + return [ |
|
25 | + 'Controller.initialize' => 'cakeEventPassThrough', |
|
26 | + 'View.beforeRender' => 'cakeEventPassThrough' |
|
27 | + ]; |
|
28 | + } |
|
29 | 29 | |
30 | - public function cakeEventPassThrough($event) { |
|
31 | - $data = ($event->data) ? : []; |
|
32 | - $data += ['subject' => $event->subject]; |
|
33 | - $name = 'Event.Saito.' . $event->name(); |
|
34 | - $this->dispatch($name, $data); |
|
35 | - } |
|
30 | + public function cakeEventPassThrough($event) { |
|
31 | + $data = ($event->data) ? : []; |
|
32 | + $data += ['subject' => $event->subject]; |
|
33 | + $name = 'Event.Saito.' . $event->name(); |
|
34 | + $this->dispatch($name, $data); |
|
35 | + } |
|
36 | 36 | |
37 | - /** |
|
38 | - * attaches event-listener |
|
39 | - * |
|
40 | - * @param string|SaitoEventListener $key |
|
41 | - * @param null $callable function if $key is set |
|
42 | - * @throws InvalidArgumentException |
|
43 | - */ |
|
44 | - public function attach($key, $callable = null) { |
|
45 | - if ($key instanceof SaitoEventListener) { |
|
46 | - foreach ($key->implementedSaitoEvents() as $eventKey => $callable) { |
|
47 | - $this->attach($eventKey, [$key, $callable]); |
|
48 | - } |
|
49 | - return; |
|
50 | - } |
|
51 | - if (empty($key)) { |
|
52 | - throw new InvalidArgumentException; |
|
53 | - } |
|
54 | - $this->_listeners[$key][] = [ |
|
55 | - 'func' => $callable, |
|
56 | - 'type' => gettype($callable) === 'array' ? 'object' : 'closure' |
|
57 | - ]; |
|
58 | - } |
|
37 | + /** |
|
38 | + * attaches event-listener |
|
39 | + * |
|
40 | + * @param string|SaitoEventListener $key |
|
41 | + * @param null $callable function if $key is set |
|
42 | + * @throws InvalidArgumentException |
|
43 | + */ |
|
44 | + public function attach($key, $callable = null) { |
|
45 | + if ($key instanceof SaitoEventListener) { |
|
46 | + foreach ($key->implementedSaitoEvents() as $eventKey => $callable) { |
|
47 | + $this->attach($eventKey, [$key, $callable]); |
|
48 | + } |
|
49 | + return; |
|
50 | + } |
|
51 | + if (empty($key)) { |
|
52 | + throw new InvalidArgumentException; |
|
53 | + } |
|
54 | + $this->_listeners[$key][] = [ |
|
55 | + 'func' => $callable, |
|
56 | + 'type' => gettype($callable) === 'array' ? 'object' : 'closure' |
|
57 | + ]; |
|
58 | + } |
|
59 | 59 | |
60 | - /** |
|
61 | - * dispatches event |
|
62 | - * |
|
63 | - * @param string $key |
|
64 | - * @param array $data |
|
65 | - * @return array|null |
|
66 | - */ |
|
67 | - public function dispatch($key, $data = []) { |
|
60 | + /** |
|
61 | + * dispatches event |
|
62 | + * |
|
63 | + * @param string $key |
|
64 | + * @param array $data |
|
65 | + * @return array|null |
|
66 | + */ |
|
67 | + public function dispatch($key, $data = []) { |
|
68 | 68 | // Stopwatch::start("SaitoEventManager::dispatch $key"); |
69 | - if (!isset($this->_listeners[$key])) { |
|
69 | + if (!isset($this->_listeners[$key])) { |
|
70 | 70 | // Stopwatch::stop("SaitoEventManager::dispatch $key"); |
71 | - return []; |
|
72 | - } |
|
73 | - $results = []; |
|
74 | - foreach ($this->_listeners[$key] as $listener) { |
|
75 | - if ($listener['type'] === 'object') { |
|
76 | - // faster than call_user_func |
|
77 | - $result = $listener['func'][0]->{$listener['func'][1]}($data); |
|
78 | - } else { |
|
79 | - $result = $listener['func']($data); |
|
80 | - } |
|
81 | - if ($result !== null) { |
|
82 | - $results[] = $result; |
|
83 | - } |
|
84 | - } |
|
71 | + return []; |
|
72 | + } |
|
73 | + $results = []; |
|
74 | + foreach ($this->_listeners[$key] as $listener) { |
|
75 | + if ($listener['type'] === 'object') { |
|
76 | + // faster than call_user_func |
|
77 | + $result = $listener['func'][0]->{$listener['func'][1]}($data); |
|
78 | + } else { |
|
79 | + $result = $listener['func']($data); |
|
80 | + } |
|
81 | + if ($result !== null) { |
|
82 | + $results[] = $result; |
|
83 | + } |
|
84 | + } |
|
85 | 85 | // Stopwatch::stop("SaitoEventManager::dispatch $key"); |
86 | - return $results; |
|
87 | - } |
|
86 | + return $results; |
|
87 | + } |
|
88 | 88 | |
89 | - } |
|
90 | 89 | \ No newline at end of file |
90 | + } |
|
91 | 91 | \ No newline at end of file |
@@ -25,7 +25,7 @@ |
||
25 | 25 | protected function _getDOMXPath($html) { |
26 | 26 | $document = new \DOMDocument; |
27 | 27 | libxml_use_internal_errors(true); |
28 | - $document->loadHTML('<!DOCTYPE html>' . $html); |
|
28 | + $document->loadHTML('<!DOCTYPE html>'.$html); |
|
29 | 29 | $xpath = new \DOMXPath($document); |
30 | 30 | libxml_clear_errors(); |
31 | 31 | return $xpath; |
@@ -18,6 +18,9 @@ |
||
18 | 18 | return $this->assertEquals($count, $length, "Failed XPath. Expected '$path' to be found $count times instead of $length."); |
19 | 19 | } |
20 | 20 | |
21 | + /** |
|
22 | + * @param string $path |
|
23 | + */ |
|
21 | 24 | public function assertNotXPath($html, $path) { |
22 | 25 | return !$this->assertXPath($html, $path, 0); |
23 | 26 | } |
@@ -1,34 +1,34 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\Test; |
|
3 | + namespace Saito\Test; |
|
4 | 4 | |
5 | - trait AssertTrait { |
|
5 | + trait AssertTrait { |
|
6 | 6 | |
7 | - /** |
|
8 | - * tests if XPath exists in HTML Source |
|
9 | - * |
|
10 | - * @param $html HTML |
|
11 | - * @param $path XPath |
|
12 | - * @param int $count how many times should XPath exist in HTML |
|
13 | - * @return mixed |
|
14 | - */ |
|
15 | - public function assertXPath($html, $path, $count = 1) { |
|
16 | - $xpath = $this->_getDOMXPath($html); |
|
17 | - $length = $xpath->query($path)->length; |
|
18 | - return $this->assertEquals($count, $length, "Failed XPath. Expected '$path' to be found $count times instead of $length."); |
|
19 | - } |
|
7 | + /** |
|
8 | + * tests if XPath exists in HTML Source |
|
9 | + * |
|
10 | + * @param $html HTML |
|
11 | + * @param $path XPath |
|
12 | + * @param int $count how many times should XPath exist in HTML |
|
13 | + * @return mixed |
|
14 | + */ |
|
15 | + public function assertXPath($html, $path, $count = 1) { |
|
16 | + $xpath = $this->_getDOMXPath($html); |
|
17 | + $length = $xpath->query($path)->length; |
|
18 | + return $this->assertEquals($count, $length, "Failed XPath. Expected '$path' to be found $count times instead of $length."); |
|
19 | + } |
|
20 | 20 | |
21 | - public function assertNotXPath($html, $path) { |
|
22 | - return !$this->assertXPath($html, $path, 0); |
|
23 | - } |
|
21 | + public function assertNotXPath($html, $path) { |
|
22 | + return !$this->assertXPath($html, $path, 0); |
|
23 | + } |
|
24 | 24 | |
25 | - protected function _getDOMXPath($html) { |
|
26 | - $document = new \DOMDocument; |
|
27 | - libxml_use_internal_errors(true); |
|
28 | - $document->loadHTML('<!DOCTYPE html>' . $html); |
|
29 | - $xpath = new \DOMXPath($document); |
|
30 | - libxml_clear_errors(); |
|
31 | - return $xpath; |
|
32 | - } |
|
25 | + protected function _getDOMXPath($html) { |
|
26 | + $document = new \DOMDocument; |
|
27 | + libxml_use_internal_errors(true); |
|
28 | + $document->loadHTML('<!DOCTYPE html>' . $html); |
|
29 | + $xpath = new \DOMXPath($document); |
|
30 | + libxml_clear_errors(); |
|
31 | + return $xpath; |
|
32 | + } |
|
33 | 33 | |
34 | - } |
|
35 | 34 | \ No newline at end of file |
35 | + } |
|
36 | 36 | \ No newline at end of file |
@@ -83,7 +83,7 @@ |
||
83 | 83 | public function assertRedirectedTo($url = '') { |
84 | 84 | $this->assertEquals( |
85 | 85 | $this->headers['Location'], |
86 | - \Router::fullBaseUrl() . $this->controller->request->webroot . $url |
|
86 | + \Router::fullBaseUrl().$this->controller->request->webroot.$url |
|
87 | 87 | ); |
88 | 88 | } |
89 | 89 |
@@ -48,6 +48,9 @@ discard block |
||
48 | 48 | unset($_ENV['HTTP_X_REQUESTED_WITH']); |
49 | 49 | } |
50 | 50 | |
51 | + /** |
|
52 | + * @param string $agent |
|
53 | + */ |
|
51 | 54 | protected function _setUserAgent($agent) { |
52 | 55 | if (isset($this->_env['HTTP_USER_AGENT'])) { |
53 | 56 | $this->_env['HTTP_USER_AGENT'] = $_ENV['HTTP_USER_AGENT']; |
@@ -63,6 +66,9 @@ discard block |
||
63 | 66 | } |
64 | 67 | } |
65 | 68 | |
69 | + /** |
|
70 | + * @param integer $id |
|
71 | + */ |
|
66 | 72 | protected function _loginUser($id) { |
67 | 73 | // see: http://stackoverflow.com/a/10411128/1372085 |
68 | 74 | $this->_logoutUser(); |
@@ -100,6 +106,9 @@ discard block |
||
100 | 106 | endif; |
101 | 107 | } |
102 | 108 | |
109 | + /** |
|
110 | + * @param string $name |
|
111 | + */ |
|
103 | 112 | protected function _notImplementedOnDatasource($name) { |
104 | 113 | $mc = $this->controller->modelClass; |
105 | 114 | $Ds = $this->controller->{$mc}->getDataSource(); |
@@ -1,8 +1,8 @@ discard block |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\Test; |
|
3 | + namespace Saito\Test; |
|
4 | 4 | |
5 | - /* |
|
5 | + /* |
|
6 | 6 | fixes early output in PHPUnit 3.7: |
7 | 7 | |
8 | 8 | $this->printer->write( |
@@ -11,128 +11,128 @@ discard block |
||
11 | 11 | |
12 | 12 | that prevents session setting in HTML test-run |
13 | 13 | */ |
14 | - ob_start(); |
|
15 | - |
|
16 | - // load fixture |
|
17 | - \App::uses('UserFixture', 'Fixture'); |
|
18 | - |
|
19 | - // sets the FULL_BASE_URL for CLI tests |
|
20 | - if (!defined('FULL_BASE_URL')) { |
|
21 | - define('FULL_BASE_URL', 'http://cakephp.org/'); |
|
22 | - } |
|
23 | - \Configure::write('App.fullBaseURL', FULL_BASE_URL); |
|
24 | - |
|
25 | - |
|
26 | - class ControllerTestCase extends \ControllerTestCase { |
|
27 | - |
|
28 | - use AssertTrait; |
|
29 | - |
|
30 | - /** |
|
31 | - * @var array cache environment variables |
|
32 | - */ |
|
33 | - protected $_env = []; |
|
34 | - |
|
35 | - protected function _setJson() { |
|
36 | - $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript'; |
|
37 | - } |
|
38 | - |
|
39 | - protected function _unsetJson() { |
|
40 | - $_SERVER['HTTP_ACCEPT'] = "text/html,application/xhtml+xml,application/xml"; |
|
41 | - } |
|
42 | - |
|
43 | - protected function _setAjax() { |
|
44 | - $_ENV['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; |
|
45 | - } |
|
46 | - |
|
47 | - protected function _unsetAjax() { |
|
48 | - unset($_ENV['HTTP_X_REQUESTED_WITH']); |
|
49 | - } |
|
50 | - |
|
51 | - protected function _setUserAgent($agent) { |
|
52 | - if (isset($this->_env['HTTP_USER_AGENT'])) { |
|
53 | - $this->_env['HTTP_USER_AGENT'] = $_ENV['HTTP_USER_AGENT']; |
|
54 | - } |
|
55 | - $_ENV['HTTP_USER_AGENT'] = $agent; |
|
56 | - } |
|
57 | - |
|
58 | - protected function _unsetUserAgent() { |
|
59 | - if (isset($this->_env['HTTP_USER_AGENT'])) { |
|
60 | - $_ENV['HTTP_USER_AGENT'] = $this->_env('HTTP_USER_AGENT'); |
|
61 | - } else { |
|
62 | - unset($_ENV['HTTP_USER_AGENT']); |
|
63 | - } |
|
64 | - } |
|
65 | - |
|
66 | - protected function _loginUser($id) { |
|
67 | - // see: http://stackoverflow.com/a/10411128/1372085 |
|
68 | - $this->_logoutUser(); |
|
69 | - $userFixture = new \UserFixture(); |
|
70 | - $users = $userFixture->records; |
|
71 | - |
|
72 | - $this->controller->Session->write('Auth.User', $users[$id - 1]); |
|
73 | - } |
|
74 | - |
|
75 | - protected function _debugEmail() { |
|
76 | - \Configure::write('Saito.Debug.email', true); |
|
77 | - } |
|
78 | - |
|
79 | - protected function _resetEmail() { |
|
80 | - \Configure::write('Saito.Debug.email', false); |
|
81 | - } |
|
82 | - |
|
83 | - public function assertRedirectedTo($url = '') { |
|
84 | - $this->assertEquals( |
|
85 | - $this->headers['Location'], |
|
86 | - \Router::fullBaseUrl() . $this->controller->request->webroot . $url |
|
87 | - ); |
|
88 | - } |
|
89 | - |
|
90 | - protected function _logoutUser() { |
|
91 | - // if user is logged-in it should interfere with test runs |
|
92 | - if (isset($_COOKIE['SaitoPersistent'])) : |
|
93 | - unset($_COOKIE['SaitoPersistent']); |
|
94 | - endif; |
|
95 | - if (isset($_COOKIE['Saito'])) : |
|
96 | - unset($_COOKIE['Saito']); |
|
97 | - endif; |
|
98 | - if (isset($this->controller->Session) && !empty($this->controller->Session)) : |
|
99 | - $this->controller->Session->delete('Auth.User'); |
|
100 | - endif; |
|
101 | - } |
|
102 | - |
|
103 | - protected function _notImplementedOnDatasource($name) { |
|
104 | - $mc = $this->controller->modelClass; |
|
105 | - $Ds = $this->controller->{$mc}->getDataSource(); |
|
106 | - $this->_DsName = get_class($Ds); |
|
107 | - if ($this->_DsName === $name) { |
|
108 | - $this->markTestIncomplete("Datasource is $name."); |
|
109 | - } |
|
110 | - } |
|
111 | - |
|
112 | - public function endTest($method) { |
|
113 | - parent::endTest($method); |
|
114 | - $this->_logoutUser(); |
|
115 | - $this->_unsetAjax(); |
|
116 | - } |
|
117 | - |
|
118 | - public function setUp() { |
|
119 | - parent::setUp(); |
|
120 | - $this->_logoutUser(); |
|
121 | - $this->_unsetAjax(); |
|
122 | - $this->_unsetJson(); |
|
123 | - $this->_debugEmail(); |
|
124 | - \Configure::write('Cache.disable', true); |
|
125 | - \Configure::write('Config.language', 'eng'); |
|
126 | - } |
|
127 | - |
|
128 | - public function tearDown() { |
|
129 | - \Configure::write('Cache.disable', false); |
|
130 | - $this->_unsetUserAgent(); |
|
131 | - $this->_resetEmail(); |
|
132 | - $this->_logoutUser(); |
|
133 | - parent::tearDown(); |
|
134 | - } |
|
135 | - |
|
136 | - } |
|
14 | + ob_start(); |
|
15 | + |
|
16 | + // load fixture |
|
17 | + \App::uses('UserFixture', 'Fixture'); |
|
18 | + |
|
19 | + // sets the FULL_BASE_URL for CLI tests |
|
20 | + if (!defined('FULL_BASE_URL')) { |
|
21 | + define('FULL_BASE_URL', 'http://cakephp.org/'); |
|
22 | + } |
|
23 | + \Configure::write('App.fullBaseURL', FULL_BASE_URL); |
|
24 | + |
|
25 | + |
|
26 | + class ControllerTestCase extends \ControllerTestCase { |
|
27 | + |
|
28 | + use AssertTrait; |
|
29 | + |
|
30 | + /** |
|
31 | + * @var array cache environment variables |
|
32 | + */ |
|
33 | + protected $_env = []; |
|
34 | + |
|
35 | + protected function _setJson() { |
|
36 | + $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript'; |
|
37 | + } |
|
38 | + |
|
39 | + protected function _unsetJson() { |
|
40 | + $_SERVER['HTTP_ACCEPT'] = "text/html,application/xhtml+xml,application/xml"; |
|
41 | + } |
|
42 | + |
|
43 | + protected function _setAjax() { |
|
44 | + $_ENV['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; |
|
45 | + } |
|
46 | + |
|
47 | + protected function _unsetAjax() { |
|
48 | + unset($_ENV['HTTP_X_REQUESTED_WITH']); |
|
49 | + } |
|
50 | + |
|
51 | + protected function _setUserAgent($agent) { |
|
52 | + if (isset($this->_env['HTTP_USER_AGENT'])) { |
|
53 | + $this->_env['HTTP_USER_AGENT'] = $_ENV['HTTP_USER_AGENT']; |
|
54 | + } |
|
55 | + $_ENV['HTTP_USER_AGENT'] = $agent; |
|
56 | + } |
|
57 | + |
|
58 | + protected function _unsetUserAgent() { |
|
59 | + if (isset($this->_env['HTTP_USER_AGENT'])) { |
|
60 | + $_ENV['HTTP_USER_AGENT'] = $this->_env('HTTP_USER_AGENT'); |
|
61 | + } else { |
|
62 | + unset($_ENV['HTTP_USER_AGENT']); |
|
63 | + } |
|
64 | + } |
|
65 | + |
|
66 | + protected function _loginUser($id) { |
|
67 | + // see: http://stackoverflow.com/a/10411128/1372085 |
|
68 | + $this->_logoutUser(); |
|
69 | + $userFixture = new \UserFixture(); |
|
70 | + $users = $userFixture->records; |
|
71 | + |
|
72 | + $this->controller->Session->write('Auth.User', $users[$id - 1]); |
|
73 | + } |
|
74 | + |
|
75 | + protected function _debugEmail() { |
|
76 | + \Configure::write('Saito.Debug.email', true); |
|
77 | + } |
|
78 | + |
|
79 | + protected function _resetEmail() { |
|
80 | + \Configure::write('Saito.Debug.email', false); |
|
81 | + } |
|
82 | + |
|
83 | + public function assertRedirectedTo($url = '') { |
|
84 | + $this->assertEquals( |
|
85 | + $this->headers['Location'], |
|
86 | + \Router::fullBaseUrl() . $this->controller->request->webroot . $url |
|
87 | + ); |
|
88 | + } |
|
89 | + |
|
90 | + protected function _logoutUser() { |
|
91 | + // if user is logged-in it should interfere with test runs |
|
92 | + if (isset($_COOKIE['SaitoPersistent'])) : |
|
93 | + unset($_COOKIE['SaitoPersistent']); |
|
94 | + endif; |
|
95 | + if (isset($_COOKIE['Saito'])) : |
|
96 | + unset($_COOKIE['Saito']); |
|
97 | + endif; |
|
98 | + if (isset($this->controller->Session) && !empty($this->controller->Session)) : |
|
99 | + $this->controller->Session->delete('Auth.User'); |
|
100 | + endif; |
|
101 | + } |
|
102 | + |
|
103 | + protected function _notImplementedOnDatasource($name) { |
|
104 | + $mc = $this->controller->modelClass; |
|
105 | + $Ds = $this->controller->{$mc}->getDataSource(); |
|
106 | + $this->_DsName = get_class($Ds); |
|
107 | + if ($this->_DsName === $name) { |
|
108 | + $this->markTestIncomplete("Datasource is $name."); |
|
109 | + } |
|
110 | + } |
|
111 | + |
|
112 | + public function endTest($method) { |
|
113 | + parent::endTest($method); |
|
114 | + $this->_logoutUser(); |
|
115 | + $this->_unsetAjax(); |
|
116 | + } |
|
117 | + |
|
118 | + public function setUp() { |
|
119 | + parent::setUp(); |
|
120 | + $this->_logoutUser(); |
|
121 | + $this->_unsetAjax(); |
|
122 | + $this->_unsetJson(); |
|
123 | + $this->_debugEmail(); |
|
124 | + \Configure::write('Cache.disable', true); |
|
125 | + \Configure::write('Config.language', 'eng'); |
|
126 | + } |
|
127 | + |
|
128 | + public function tearDown() { |
|
129 | + \Configure::write('Cache.disable', false); |
|
130 | + $this->_unsetUserAgent(); |
|
131 | + $this->_resetEmail(); |
|
132 | + $this->_logoutUser(); |
|
133 | + parent::tearDown(); |
|
134 | + } |
|
135 | + |
|
136 | + } |
|
137 | 137 | |
138 | 138 |
@@ -60,7 +60,7 @@ |
||
60 | 60 | } |
61 | 61 | |
62 | 62 | protected function _registerGc(\CronComponent $Cron) { |
63 | - $Cron->addCronJob('ReadUser.' . $this->_id(), 'hourly', [$this, 'gcUser']); |
|
63 | + $Cron->addCronJob('ReadUser.'.$this->_id(), 'hourly', [$this, 'gcUser']); |
|
64 | 64 | $Cron->addCronJob('ReadUser.global', 'hourly', [$this, 'gcGlobal']); |
65 | 65 | } |
66 | 66 |
@@ -1,143 +1,143 @@ |
||
1 | 1 | <?php |
2 | 2 | |
3 | - namespace Saito\User\ReadPostings; |
|
4 | - |
|
5 | - /** |
|
6 | - * Handles read postings by a server table. Used for logged-in users. |
|
7 | - */ |
|
8 | - class ReadPostingsDatabase extends ReadPostingsAbstract { |
|
9 | - |
|
10 | - protected $_UserRead; |
|
11 | - |
|
12 | - protected $_minPostingsToKeep; |
|
13 | - |
|
14 | - public function __construct(\CurrentUserComponent $CurrentUser) { |
|
15 | - parent::__construct($CurrentUser); |
|
16 | - $this->_UserRead = $this->_CurrentUser->getModel()->UserRead; |
|
17 | - $this->_registerGc($this->_CurrentUser->Cron); |
|
18 | - } |
|
19 | - |
|
20 | - /** |
|
21 | - * @throws InvalidArgumentException |
|
22 | - */ |
|
23 | - public function set($entries) { |
|
24 | - \Stopwatch::start('ReadPostingsDatabase::set()'); |
|
25 | - if (!$this->_CurrentUser->isLoggedIn()) { |
|
26 | - return; |
|
27 | - } |
|
28 | - |
|
29 | - $entries = $this->_preparePostings($entries); |
|
30 | - if (empty($entries)) { |
|
31 | - return; |
|
32 | - } |
|
33 | - |
|
34 | - $this->_UserRead->setEntriesForUser($entries, $this->_id()); |
|
35 | - \Stopwatch::stop('ReadPostingsDatabase::set()'); |
|
36 | - } |
|
37 | - |
|
38 | - public function delete() { |
|
39 | - $this->_UserRead->deleteAllFromUser($this->_id()); |
|
40 | - } |
|
41 | - |
|
42 | - /** |
|
43 | - * calculates user quota of allowed entries in DB |
|
44 | - * |
|
45 | - * @return int |
|
46 | - * @throws \UnexpectedValueException |
|
47 | - */ |
|
48 | - protected function _minNPostingsToKeep() { |
|
49 | - if ($this->_minPostingsToKeep) { |
|
50 | - return $this->_minPostingsToKeep; |
|
51 | - } |
|
52 | - $threadsOnPage = \Configure::read('Saito.Settings.topics_per_page'); |
|
53 | - $postingsPerThread = \Configure::read('Saito.Globals.postingsPerThread'); |
|
54 | - $pagesToCache = 1.5; |
|
55 | - $this->_minPostingsToKeep = intval($postingsPerThread * $threadsOnPage * $pagesToCache); |
|
56 | - if (empty($this->_minPostingsToKeep)) { |
|
57 | - throw new \UnexpectedValueException(); |
|
58 | - } |
|
59 | - return $this->_minPostingsToKeep; |
|
60 | - } |
|
61 | - |
|
62 | - protected function _registerGc(\CronComponent $Cron) { |
|
63 | - $Cron->addCronJob('ReadUser.' . $this->_id(), 'hourly', [$this, 'gcUser']); |
|
64 | - $Cron->addCronJob('ReadUser.global', 'hourly', [$this, 'gcGlobal']); |
|
65 | - } |
|
66 | - |
|
67 | - /** |
|
68 | - * removes old data from non-active users |
|
69 | - * |
|
70 | - * should prevent entries of non returning users to stay forever in DB |
|
71 | - */ |
|
72 | - public function gcGlobal() { |
|
73 | - $lastEntry = $this->_CurrentUser->getModel()->Entry->find('first', |
|
74 | - [ |
|
75 | - 'contain' => false, |
|
76 | - 'fields' => ['Entry.id'], |
|
77 | - 'order' => ['Entry.id' => 'DESC'] |
|
78 | - ]); |
|
79 | - if (!$lastEntry) { |
|
80 | - return; |
|
81 | - } |
|
82 | - // @bogus why not getModel()->Entry->Category |
|
83 | - $Category = \ClassRegistry::init('Category'); |
|
84 | - $nCategories = $Category->find('count'); |
|
85 | - $entriesToKeep = $nCategories * $this->_minNPostingsToKeep(); |
|
86 | - $lastEntryId = $lastEntry['Entry']['id'] - $entriesToKeep; |
|
87 | - $this->_UserRead->deleteEntriesBefore($lastEntryId); |
|
88 | - } |
|
89 | - |
|
90 | - /** |
|
91 | - * removes old data from current users |
|
92 | - * |
|
93 | - * should prevent endless growing of DB if user never clicks the MAR-button |
|
94 | - */ |
|
95 | - public function gcUser() { |
|
96 | - if (!$this->_CurrentUser->isLoggedIn()) { |
|
97 | - return; |
|
98 | - } |
|
99 | - |
|
100 | - $entries = $this->_get(); |
|
101 | - $numberOfEntries = count($entries); |
|
102 | - if ($numberOfEntries === 0) { |
|
103 | - return; |
|
104 | - } |
|
105 | - |
|
106 | - $maxEntriesToKeep = $this->_minNPostingsToKeep(); |
|
107 | - if ($numberOfEntries <= $maxEntriesToKeep) { |
|
108 | - return; |
|
109 | - } |
|
110 | - |
|
111 | - $entriesToDelete = $numberOfEntries - $maxEntriesToKeep; |
|
112 | - // assign dummy var to prevent Strict notice on reference passing |
|
113 | - $dummy = array_slice($entries, $entriesToDelete, 1); |
|
114 | - $oldestIdToKeep = array_shift($dummy); |
|
115 | - $this->_UserRead->deleteUserEntriesBefore($this->_id(), $oldestIdToKeep); |
|
116 | - |
|
117 | - // all entries older than (and including) the deleted entries become |
|
118 | - // old entries by updating the MAR-timestamp |
|
119 | - $youngestDeletedEntry = $this->_CurrentUser->getModel()->Entry->find('first', |
|
120 | - [ |
|
121 | - 'contain' => false, |
|
122 | - 'conditions' => ['Entry.id' => $oldestIdToKeep], |
|
123 | - 'fields' => ['Entry.time'] |
|
124 | - ]); |
|
125 | - // can't use $this->_CU->LastRefresh->set() because this would also |
|
126 | - // delete all of this user's UserRead entries |
|
127 | - $this->_CurrentUser->getModel() |
|
128 | - ->setLastRefresh($youngestDeletedEntry['Entry']['time']); |
|
129 | - } |
|
130 | - |
|
131 | - protected function _get() { |
|
132 | - if ($this->_readPostings !== null) { |
|
133 | - return $this->_readPostings; |
|
134 | - } |
|
135 | - $this->_readPostings = $this->_UserRead->getUser($this->_id()); |
|
136 | - return $this->_readPostings; |
|
137 | - } |
|
138 | - |
|
139 | - protected function _id() { |
|
140 | - return $this->_CurrentUser->getId(); |
|
141 | - } |
|
142 | - |
|
143 | - } |
|
3 | + namespace Saito\User\ReadPostings; |
|
4 | + |
|
5 | + /** |
|
6 | + * Handles read postings by a server table. Used for logged-in users. |
|
7 | + */ |
|
8 | + class ReadPostingsDatabase extends ReadPostingsAbstract { |
|
9 | + |
|
10 | + protected $_UserRead; |
|
11 | + |
|
12 | + protected $_minPostingsToKeep; |
|
13 | + |
|
14 | + public function __construct(\CurrentUserComponent $CurrentUser) { |
|
15 | + parent::__construct($CurrentUser); |
|
16 | + $this->_UserRead = $this->_CurrentUser->getModel()->UserRead; |
|
17 | + $this->_registerGc($this->_CurrentUser->Cron); |
|
18 | + } |
|
19 | + |
|
20 | + /** |
|
21 | + * @throws InvalidArgumentException |
|
22 | + */ |
|
23 | + public function set($entries) { |
|
24 | + \Stopwatch::start('ReadPostingsDatabase::set()'); |
|
25 | + if (!$this->_CurrentUser->isLoggedIn()) { |
|
26 | + return; |
|
27 | + } |
|
28 | + |
|
29 | + $entries = $this->_preparePostings($entries); |
|
30 | + if (empty($entries)) { |
|
31 | + return; |
|
32 | + } |
|
33 | + |
|
34 | + $this->_UserRead->setEntriesForUser($entries, $this->_id()); |
|
35 | + \Stopwatch::stop('ReadPostingsDatabase::set()'); |
|
36 | + } |
|
37 | + |
|
38 | + public function delete() { |
|
39 | + $this->_UserRead->deleteAllFromUser($this->_id()); |
|
40 | + } |
|
41 | + |
|
42 | + /** |
|
43 | + * calculates user quota of allowed entries in DB |
|
44 | + * |
|
45 | + * @return int |
|
46 | + * @throws \UnexpectedValueException |
|
47 | + */ |
|
48 | + protected function _minNPostingsToKeep() { |
|
49 | + if ($this->_minPostingsToKeep) { |
|
50 | + return $this->_minPostingsToKeep; |
|
51 | + } |
|
52 | + $threadsOnPage = \Configure::read('Saito.Settings.topics_per_page'); |
|
53 | + $postingsPerThread = \Configure::read('Saito.Globals.postingsPerThread'); |
|
54 | + $pagesToCache = 1.5; |
|
55 | + $this->_minPostingsToKeep = intval($postingsPerThread * $threadsOnPage * $pagesToCache); |
|
56 | + if (empty($this->_minPostingsToKeep)) { |
|
57 | + throw new \UnexpectedValueException(); |
|
58 | + } |
|
59 | + return $this->_minPostingsToKeep; |
|
60 | + } |
|
61 | + |
|
62 | + protected function _registerGc(\CronComponent $Cron) { |
|
63 | + $Cron->addCronJob('ReadUser.' . $this->_id(), 'hourly', [$this, 'gcUser']); |
|
64 | + $Cron->addCronJob('ReadUser.global', 'hourly', [$this, 'gcGlobal']); |
|
65 | + } |
|
66 | + |
|
67 | + /** |
|
68 | + * removes old data from non-active users |
|
69 | + * |
|
70 | + * should prevent entries of non returning users to stay forever in DB |
|
71 | + */ |
|
72 | + public function gcGlobal() { |
|
73 | + $lastEntry = $this->_CurrentUser->getModel()->Entry->find('first', |
|
74 | + [ |
|
75 | + 'contain' => false, |
|
76 | + 'fields' => ['Entry.id'], |
|
77 | + 'order' => ['Entry.id' => 'DESC'] |
|
78 | + ]); |
|
79 | + if (!$lastEntry) { |
|
80 | + return; |
|
81 | + } |
|
82 | + // @bogus why not getModel()->Entry->Category |
|
83 | + $Category = \ClassRegistry::init('Category'); |
|
84 | + $nCategories = $Category->find('count'); |
|
85 | + $entriesToKeep = $nCategories * $this->_minNPostingsToKeep(); |
|
86 | + $lastEntryId = $lastEntry['Entry']['id'] - $entriesToKeep; |
|
87 | + $this->_UserRead->deleteEntriesBefore($lastEntryId); |
|
88 | + } |
|
89 | + |
|
90 | + /** |
|
91 | + * removes old data from current users |
|
92 | + * |
|
93 | + * should prevent endless growing of DB if user never clicks the MAR-button |
|
94 | + */ |
|
95 | + public function gcUser() { |
|
96 | + if (!$this->_CurrentUser->isLoggedIn()) { |
|
97 | + return; |
|
98 | + } |
|
99 | + |
|
100 | + $entries = $this->_get(); |
|
101 | + $numberOfEntries = count($entries); |
|
102 | + if ($numberOfEntries === 0) { |
|
103 | + return; |
|
104 | + } |
|
105 | + |
|
106 | + $maxEntriesToKeep = $this->_minNPostingsToKeep(); |
|
107 | + if ($numberOfEntries <= $maxEntriesToKeep) { |
|
108 | + return; |
|
109 | + } |
|
110 | + |
|
111 | + $entriesToDelete = $numberOfEntries - $maxEntriesToKeep; |
|
112 | + // assign dummy var to prevent Strict notice on reference passing |
|
113 | + $dummy = array_slice($entries, $entriesToDelete, 1); |
|
114 | + $oldestIdToKeep = array_shift($dummy); |
|
115 | + $this->_UserRead->deleteUserEntriesBefore($this->_id(), $oldestIdToKeep); |
|
116 | + |
|
117 | + // all entries older than (and including) the deleted entries become |
|
118 | + // old entries by updating the MAR-timestamp |
|
119 | + $youngestDeletedEntry = $this->_CurrentUser->getModel()->Entry->find('first', |
|
120 | + [ |
|
121 | + 'contain' => false, |
|
122 | + 'conditions' => ['Entry.id' => $oldestIdToKeep], |
|
123 | + 'fields' => ['Entry.time'] |
|
124 | + ]); |
|
125 | + // can't use $this->_CU->LastRefresh->set() because this would also |
|
126 | + // delete all of this user's UserRead entries |
|
127 | + $this->_CurrentUser->getModel() |
|
128 | + ->setLastRefresh($youngestDeletedEntry['Entry']['time']); |
|
129 | + } |
|
130 | + |
|
131 | + protected function _get() { |
|
132 | + if ($this->_readPostings !== null) { |
|
133 | + return $this->_readPostings; |
|
134 | + } |
|
135 | + $this->_readPostings = $this->_UserRead->getUser($this->_id()); |
|
136 | + return $this->_readPostings; |
|
137 | + } |
|
138 | + |
|
139 | + protected function _id() { |
|
140 | + return $this->_CurrentUser->getId(); |
|
141 | + } |
|
142 | + |
|
143 | + } |