/wp-content/plugins/simple-lightbox/includes/class.base_collection.php

https://github.com/Canuckaholic/Pop-Digital · PHP · 369 lines · 181 code · 30 blank · 158 comment · 46 complexity · 723e5e0b819c56cd1fbe4728e6b31790 MD5 · raw file

  1. <?php
  2. /**
  3. * Managed collection
  4. * @package Simple Lightbox
  5. * @subpackage Base
  6. * @author Archetyped
  7. */
  8. class SLB_Base_Collection extends SLB_Base {
  9. /* Configuration */
  10. /**
  11. * Set object mode
  12. * @var string
  13. */
  14. protected $mode = 'object';
  15. /**
  16. * Item type
  17. * @var string
  18. */
  19. protected $item_type = null;
  20. /**
  21. * Property to use for item key
  22. * Example: A property or method of the item
  23. * @var string
  24. */
  25. protected $key_prop = null;
  26. /**
  27. * Should $key_prop be called or retrieved?
  28. * Default: Retrieved (FALSE)
  29. * @var bool
  30. */
  31. protected $key_call = false;
  32. /**
  33. * Items in collection unique?
  34. * Default: FALSE
  35. * @var bool
  36. */
  37. protected $unique = false;
  38. /* Properties */
  39. /**
  40. * Indexed array of items in collection
  41. * @var array
  42. */
  43. protected $items = null;
  44. /**
  45. * Item metadata
  46. * Indexed by item key
  47. * @var array
  48. */
  49. protected $items_meta = array();
  50. /* Item Management */
  51. /**
  52. * Initialize collections
  53. * Calls `init` action if collection has a hook prefix
  54. */
  55. private function init() {
  56. //Initialize
  57. if ( is_null($this->items) ) {
  58. $this->items = array();
  59. if ( !empty($this->hook_prefix) ) {
  60. $this->util->do_action('init', $this);
  61. }
  62. }
  63. }
  64. /**
  65. * Normalize/Validate item(s)
  66. * TODO: If no items are specified, then collection is normalized
  67. * Single items are wrapped in an array
  68. * @param array|object $items Item(s) to validate
  69. * @return array Validated items
  70. */
  71. protected function normalize($items) {
  72. if ( !is_array($items) ) {
  73. $items = array($items);
  74. }
  75. //Validate item type
  76. if ( !is_null($this->item_type) ) {
  77. foreach ( $items as $idx => $item ) {
  78. //Remove invalid items
  79. if ( !( $item instanceof $this->item_type ) ) {
  80. unset($items[$idx]);
  81. }
  82. }
  83. }
  84. if ( !empty($items) ) {
  85. $items = array_values($items);
  86. }
  87. return $items;
  88. }
  89. protected function item_valid($item) {
  90. //Validate item type
  91. return ( empty($this->item_type) || ( $item instanceof $this->item_type ) ) ? true : false;
  92. }
  93. /**
  94. * Validate item key
  95. * Checks collection for existence of key as well
  96. * @param string|int $key Key to check collection for
  97. * @return bool TRUE if key is valid
  98. */
  99. protected function key_valid($key) {
  100. $this->init();
  101. return ( ( ( is_string($key) && !empty($key) ) || is_int($key) ) && isset($this->items[$key]) ) ? true : false;
  102. }
  103. /**
  104. * Generate key for item (for storing in collection, etc.)
  105. * @param mixed $item Item to generate key for
  106. * @return string|null Item key (NULL if no key generated)
  107. */
  108. protected function get_key($item, $check_existing = false) {
  109. $ret = null;
  110. if ( $this->unique || !!$check_existing ) {
  111. //Check for item in collection
  112. if ( $this->has($item) ) {
  113. $ret = array_search($item, $this->items);
  114. } elseif ( !!$this->key_prop && ( is_object($item) || is_array($item) ) ) {
  115. if ( !!$this->key_call ) {
  116. $cb = $this->util->m($item, $this->key_prop);
  117. if ( is_callable($cb) ) {
  118. $ret = call_user_func($cb);
  119. }
  120. } elseif ( is_array($item) && isset($item[$this->key_prop]) ) {
  121. $ret = $item[$this->key_prop];
  122. } elseif ( is_object($item) && isset($item->{$this->key_prop}) ) {
  123. $ret = $item->{$this->key_prop};
  124. }
  125. }
  126. }
  127. return $ret;
  128. }
  129. /**
  130. * Add item to collection
  131. * @param mixed $item Item to add to collection
  132. * @param array $meta (optional) Item metadata
  133. * @return Current instance
  134. */
  135. public function add($item, $meta = null) {
  136. $this->init();
  137. //Validate
  138. if ( $this->item_valid($item) ) {
  139. //Add item to collection
  140. $key = $this->get_key($item);
  141. if ( !$key ) {
  142. $this->items[] = $item;
  143. $key = key($this->items);
  144. } else {
  145. $this->items[$key] = $item;
  146. }
  147. //Add metadata
  148. if ( !!$key && is_array($meta) ) {
  149. $this->add_meta($key, $meta);
  150. }
  151. }
  152. return $this;
  153. }
  154. /**
  155. * Remove item from collection
  156. * @param int|string $item Key of item to remove
  157. * @return Current instance
  158. */
  159. public function remove($item) {
  160. if ( $this->key_valid($item) ) {
  161. unset($this->items[$item]);
  162. }
  163. return $this;
  164. }
  165. /**
  166. * Clear collection
  167. * @return Current instance
  168. */
  169. public function clear() {
  170. $this->items = array();
  171. return $this;
  172. }
  173. /**
  174. * Checks if item exists in the collection
  175. * @param mixed $item Item(s) to check for
  176. * @return bool TRUE if item(s) in collection
  177. */
  178. public function has($items) {
  179. //Attempt to locate item
  180. return false;
  181. }
  182. /**
  183. * Retrieve item(s) from collection
  184. * If no items specified, entire collection returned
  185. * @param array $args (optional) Query arguments
  186. * @return object|array Specified item(s)
  187. */
  188. public function get($args = null) {
  189. $this->init();
  190. //Parse args
  191. $args_default = array(
  192. 'orderby' => null,
  193. 'order' => 'DESC',
  194. 'include' => array(),
  195. 'exclude' => array(),
  196. );
  197. $r = wp_parse_args($args, $args_default);
  198. $items = $this->items;
  199. /* Sort */
  200. if ( !is_null($r['orderby']) ) {
  201. //Validate
  202. if ( !is_array($r['orderby']) ) {
  203. $r['orderby'] = array('item' => $r['orderby']);
  204. }
  205. //Prep
  206. $metas = ( isset($r['orderby']['meta']) ) ? $this->items_meta : array();
  207. //Sort
  208. foreach ( $r['orderby'] as $stype => $sval ) {
  209. /* Meta sorting */
  210. if ( 'meta' == $stype ) {
  211. //Build sorting buckets
  212. $buckets = array();
  213. foreach ( $metas as $item => $meta ) {
  214. if ( !isset($meta[$sval]) ) {
  215. continue;
  216. }
  217. //Create bucket
  218. $idx = $meta[$sval];
  219. if ( !isset($buckets[ $idx ]) ) {
  220. $buckets[ $idx ] = array();
  221. }
  222. //Add item to bucket
  223. $buckets[ $idx ][] = $item;
  224. }
  225. //Sort buckets
  226. ksort($buckets, SORT_NUMERIC);
  227. //Merge buckets
  228. $pool = array();
  229. foreach ( $buckets as $bucket ) {
  230. $pool = array_merge($pool, $bucket);
  231. }
  232. //Fill with items
  233. $items = array_merge( array_fill_keys($pool, null), $items);
  234. }
  235. }
  236. //Clear workers
  237. unset($stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx);
  238. }
  239. return $items;
  240. }
  241. /* Metadata */
  242. /**
  243. * Add metadata for item
  244. * @param string|int $item Item key
  245. * @param string|array $meta_key Meta key to set (or array of metadata)
  246. * @param mixed $meta_value (optional) Metadata value (if key set)
  247. * @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE)
  248. * @return object Current instance
  249. */
  250. protected function add_meta($item, $meta_key, $meta_value = null, $reset = false) {
  251. //Validate
  252. if ( $this->key_valid($item) && ( is_array($meta_key) || is_string($meta_key) ) ) {
  253. //Prepare metadata
  254. $meta = ( is_string($meta_key) ) ? array($meta_key => $meta_value) : $meta_key;
  255. //Reset existing meta (if necessary)
  256. if ( is_array($meta_key) && func_num_args() > 2) {
  257. $reset = func_get_arg(2);
  258. }
  259. if ( !!$reset ) {
  260. unset($this->items_meta[$item]);
  261. }
  262. //Add metadata
  263. if ( !isset($this->items_meta[$item]) ) {
  264. $this->items_meta[$item] = array();
  265. }
  266. $this->items_meta[$item] = array_merge($this->items_meta[$item], $meta);
  267. }
  268. return $this;
  269. }
  270. /**
  271. * Remove item metadata
  272. * @param string $item Item key
  273. * @return object Current instance
  274. */
  275. protected function remove_meta($item, $meta_key = null) {
  276. if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) {
  277. if ( is_string($meta_key) ) {
  278. //Remove specific meta value
  279. unset($this->items_meta[$item][$meta_key]);
  280. } else {
  281. //Remove all metadata
  282. unset($this->items_meta[$item]);
  283. }
  284. }
  285. return $this;
  286. }
  287. /**
  288. * Retrieve metadata
  289. * @param string $item Item key
  290. * @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified)
  291. * @return mixed|null Metadata value
  292. */
  293. protected function get_meta($item, $meta_key = null) {
  294. $ret = null;
  295. if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) {
  296. if ( is_null($meta_key) ) {
  297. $ret = $this->items_meta[$item];
  298. } elseif ( is_string($meta_key) && isset($this->items_meta[$item][$meta_key]) ) {
  299. $ret = $this->items_meta[$item][$meta_key];
  300. }
  301. }
  302. return $ret;
  303. }
  304. /* Collection */
  305. /**
  306. * Build entire collection of items
  307. * Prints output
  308. */
  309. function build($build_vars = array()) {
  310. //Parse vars
  311. $this->parse_build_vars($build_vars);
  312. $this->util->do_action_ref_array('build_init', array($this));
  313. //Pre-build output
  314. $this->util->do_action_ref_array('build_pre', array($this));
  315. //Build groups
  316. $this->build_groups();
  317. //Post-build output
  318. $this->util->do_action_ref_array('build_post', array($this));
  319. }
  320. /**
  321. * Parses build variables prior to use
  322. * @uses this->reset_build_vars() to reset build variables for each request
  323. * @param array $build_vars Variables to use for current request
  324. */
  325. function parse_build_vars($build_vars = array()) {
  326. $this->reset_build_vars();
  327. $this->build_vars = $this->util->apply_filters('parse_build_vars', wp_parse_args($build_vars, $this->build_vars), $this);
  328. }
  329. /**
  330. * Reset build variables to defaults
  331. * Default Variables
  332. * > groups - array - Names of groups to build
  333. * > context - string - Context of current request
  334. * > layout - string - Name of default layout to use
  335. */
  336. function reset_build_vars() {
  337. $this->build_vars = wp_parse_args($this->build_vars, $this->build_vars_default);
  338. }
  339. }