PageRenderTime 27ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/CMS/src/Model/Behavior/SerializableBehavior.php

http://github.com/QuickAppsCMS/QuickApps-CMS
PHP | 195 lines | 75 code | 11 blank | 109 comment | 13 complexity | a84c7d9eed2e6a21e2aa4aa836cc5051 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. <?php
  2. /**
  3. * Licensed under The GPL-3.0 License
  4. * For full copyright and license information, please see the LICENSE.txt
  5. * Redistributions of files must retain the above copyright notice.
  6. *
  7. * @since 2.0.0
  8. * @author Christopher Castro <chris@quickapps.es>
  9. * @link http://www.quickappscms.org
  10. * @license http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
  11. */
  12. namespace CMS\Model\Behavior;
  13. use Cake\Database\Type;
  14. use Cake\Datasource\EntityInterface;
  15. use Cake\Event\Event;
  16. use Cake\ORM\Behavior;
  17. use Cake\ORM\Query;
  18. use Cake\ORM\Table;
  19. use Cake\Utility\Hash;
  20. use \ArrayObject;
  21. /**
  22. * Serializable Behavior.
  23. *
  24. * Allows store serializable information into table columns.
  25. */
  26. class SerializableBehavior extends Behavior
  27. {
  28. /**
  29. * Default configuration.
  30. *
  31. * @var array
  32. */
  33. protected $_defaultConfig = [
  34. 'columns' => [],
  35. ];
  36. /**
  37. * Constructor
  38. *
  39. * Merges config with the default and store in the config property
  40. *
  41. * @param \Cake\ORM\Table $table The table this behavior is attached to.
  42. * @param array $config The config for this behavior.
  43. */
  44. public function __construct(Table $table, array $config = [])
  45. {
  46. if (isset($config['columns']) && is_string($config['columns'])) {
  47. $config['columns'] = [$config['columns']];
  48. }
  49. parent::__construct($table, $config);
  50. if (!Type::map('serialized')) {
  51. Type::map('serialized', 'CMS\Database\Type\SerializedType');
  52. }
  53. foreach ($this->config('columns') as $column) {
  54. $this->_table->schema()->columnType($column, 'serialized');
  55. }
  56. }
  57. /**
  58. * Triggered before data is converted into entities.
  59. *
  60. * Moves multi-value POST data into its corresponding column, for instance given
  61. * the following POST array:
  62. *
  63. * ```php
  64. * [
  65. * 'settings:max_time' => 10,
  66. * 'settings:color' => '#005599',
  67. * 'my_column:other_option' => 'some value',
  68. * ]
  69. * ```
  70. *
  71. * It becomes:
  72. *
  73. * ```php
  74. * [
  75. * 'settings' => [
  76. * 'max_time' => 10,
  77. * 'color' => '#005599',
  78. * ],
  79. * 'my_column' => [
  80. * 'other_option' => 'some value',
  81. * ]
  82. * ]
  83. * ```
  84. *
  85. * @param \Cake\Event\Event $event The event that was triggered
  86. * @param \ArrayObject $data The POST data to be merged with entity
  87. * @param \ArrayObject $options The options passed to the marshaller
  88. * @return void
  89. */
  90. public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
  91. {
  92. $dataArray = Hash::expand((array)$data, ':');
  93. foreach ($this->config('columns') as $column) {
  94. if (isset($dataArray[$column])) {
  95. $data[$column] = $dataArray[$column];
  96. if ($options['validate']) {
  97. $eventName = $this->_table->alias() . ".{$column}.validate";
  98. $columnData = (array)$dataArray[$column];
  99. $this->_table->dispatchEvent($eventName, compact('columnData', 'options'));
  100. }
  101. }
  102. }
  103. }
  104. /**
  105. * Here we set default values for serializable columns.
  106. *
  107. * This method triggers the `<TableAlias>.<columnName>.defaultValues` event, for
  108. * example "Plugins.settings.defaultValues" for the "settings" columns of the
  109. * "Plugins" table. Event listeners should catch this event and provides the
  110. * desired values.
  111. *
  112. * ### Options:
  113. *
  114. * - flatten: Flattens serialized information into plain entity properties, for
  115. * example `settings:some_option` => `value`, where `settings` is the
  116. * serialized column and `some_option` a key of the serialized array value.
  117. * Valid only for column that stores array values. Example:
  118. *
  119. * Consider the following entity:
  120. *
  121. * ```php
  122. * object(Cake\Datasource\EntityInterface) {
  123. * 'settings' => [
  124. * 'option_1' => 'Lorem ipsum',
  125. * 'option_2' => [1, 2, 3, 4],
  126. * 'option_3' => object,
  127. * ],
  128. * }
  129. * ```
  130. *
  131. * Once `settings` column is flattened the entity will look as follow:
  132. *
  133. * ```php
  134. * object(Cake\Datasource\EntityInterface) {
  135. * 'settings' => [
  136. * 'option_1' => 'Lorem ipsum',
  137. * 'option_2' => [1, 2, 3, 4],
  138. * 'option_3' => object,
  139. * ],
  140. * 'settings:option_1' => 'Lorem ipsum',
  141. * 'settings:option_2' => [1, 2, 3, 4],
  142. * 'settings:option_3' => object,
  143. * }
  144. * ```
  145. *
  146. * @param \Cake\Event\Event $event The event that was triggered
  147. * @param \Cake\ORM\Query $query Query object
  148. * @param \ArrayObject $options Additional options as an array
  149. * @param bool $primary Whether is find is a primary query or not
  150. * @return void
  151. */
  152. public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
  153. {
  154. $query->formatResults(function ($results) use ($options) {
  155. return $results->map(function ($entity) use ($options) {
  156. if (!($entity instanceof EntityInterface)) {
  157. return $entity;
  158. }
  159. foreach ($this->config('columns') as $column) {
  160. if ($entity->has($column)) {
  161. $eventName = $this->_table->alias() . ".{$column}.defaultValues";
  162. $defaultValue = $this->_table->dispatchEvent($eventName, compact('entity'))->result;
  163. $currentValue = $entity->get($column);
  164. $newValue = $currentValue;
  165. if (is_array($currentValue) && is_array($defaultValue)) {
  166. $newValue = Hash::merge($defaultValue, $currentValue);
  167. } elseif (is_string($currentValue) && $currentValue === '') {
  168. $newValue = $defaultValue;
  169. } elseif (empty($currentValue) && !empty($defaultValue)) {
  170. $newValue = $defaultValue;
  171. }
  172. $entity->set($column, $newValue);
  173. if (!empty($options['flatten']) && is_array($entity->get($column))) {
  174. foreach ($entity->get($column) as $key => $value) {
  175. $entity->set("{$column}:{$key}", $value);
  176. }
  177. }
  178. }
  179. }
  180. return $entity;
  181. });
  182. });
  183. }
  184. }