/library/DataGrid/DataGrid.php

https://github.com/widmogrod/data-grid · PHP · 373 lines · 249 code · 50 blank · 74 comment · 22 complexity · e544a43f218cfe132881142316bb2308 MD5 · raw file

  1. <?php
  2. /**
  3. * @author gabriel
  4. */
  5. namespace DataGrid;
  6. use DataGrid\EventManager\EventManagerInterface;
  7. use DataGrid\EventManager\EventManager;
  8. use DataGrid\EventManager\GridEvent;
  9. use DataGrid\EventManager\Result\ResultInterface;
  10. use DataGrid\EventManager\ListenerInterface;
  11. use DataGrid\StateStorage\StateStorageInterface;
  12. use DataGrid\StateStorage\Get;
  13. class DataGrid
  14. {
  15. /**#@+
  16. * Types of data elements
  17. *
  18. * @var string
  19. */
  20. const CELL = 'cell';
  21. const COLUMN = 'column';
  22. const ACTIONS = 'actions';
  23. /**#@+*/
  24. /**
  25. * Provided data adapter
  26. *
  27. * @var Adapter\AdapterInterface
  28. */
  29. protected $adapter;
  30. /**
  31. * Rendering strategy
  32. *
  33. * @var Renderer\RendererInterface
  34. */
  35. protected $renderer;
  36. /**
  37. * Event manager
  38. *
  39. * @var EventManagerInterface
  40. */
  41. protected $eventManager;
  42. /**
  43. * Data grid state storage
  44. *
  45. * @var StateStorageInterface
  46. */
  47. protected $stateStorage;
  48. /**
  49. * List of shipped with DataGrid data adapters
  50. *
  51. * @var array
  52. */
  53. protected $invokableAdapters = array(
  54. 'doctrine' => 'DataGrid\Adapter\Doctrine',
  55. 'ArrayObject' => 'DataGrid\Adapter\ArrayObject',
  56. );
  57. /**
  58. * List of data types that will be wrapped by predefined adapter
  59. *
  60. * @var array
  61. */
  62. protected $dataTypeToAdapter = array(
  63. 'Doctrine\ORM\NativeQuery' => 'doctrine',
  64. 'Doctrine\ORM\Query' => 'doctrine',
  65. 'array' => 'ArrayObject',
  66. 'ArrayObject' => 'ArrayObject',
  67. );
  68. protected $specialColumns = array();
  69. public function __construct($dataOrAdapter = null, array $options = null)
  70. {
  71. if (null !== $options) {
  72. $this->setOptions($options);
  73. }
  74. if (null !== $dataOrAdapter) {
  75. $this->setAdapter($dataOrAdapter);
  76. }
  77. }
  78. protected function setOptions($options)
  79. {
  80. $methodWithAddPrefix = array(
  81. 'invokableAdapters' => true,
  82. 'dataTypesToAdapter' => true,
  83. );
  84. foreach($options as $key => $value) {
  85. $prefix = isset($methodWithAddPrefix[$key]) ? 'add' : 'set';
  86. $method = $prefix . ucfirst($key);
  87. if (method_exists($this, $method)) {
  88. $this->$method($value);
  89. }
  90. }
  91. }
  92. public function addInvokableAdapters(array $adapters) {
  93. $this->invokableAdapters = array_merge(
  94. $this->invokableAdapters,
  95. $adapters
  96. );
  97. }
  98. public function addDataTypesToAdapter(array $dataTypesToAdapter) {
  99. $this->dataTypeToAdapter = array_merge(
  100. $this->dataTypeToAdapter,
  101. $dataTypesToAdapter
  102. );
  103. }
  104. public function setAdapter($dataOrAdapter)
  105. {
  106. if (!($dataOrAdapter instanceof Adapter\AdapterInterface))
  107. {
  108. $dataType = is_object($dataOrAdapter)
  109. ? get_class($dataOrAdapter)
  110. : gettype($dataOrAdapter);
  111. if (!isset($this->dataTypeToAdapter[$dataType])) {
  112. $message = 'Given data is not instance of "DataGrid\Adapter\AdapterInterface" ' .
  113. 'and data type "%s" can\'t be wrapped by existing adapters (%s)';
  114. $message = sprintf(
  115. $message,
  116. $dataType,
  117. implode(', ', array_map(function($key, $value){
  118. return "$key => $value";
  119. }, array_keys($this->dataTypeToAdapter), $this->dataTypeToAdapter))
  120. );
  121. throw new Exception\InvalidArgumentException($message);
  122. }
  123. $adapterAlias = $this->dataTypeToAdapter[$dataType];
  124. if (!isset($this->invokableAdapters[$adapterAlias])) {
  125. if (!class_exists($adapterAlias)) {
  126. $message = 'Given adapter alias "%s" for data type "%s" ' .
  127. 'can\'t be wrapped by known adapters (%s)';
  128. $message = sprintf(
  129. $message,
  130. $adapterAlias,
  131. $dataType,
  132. implode(', ', array_map(function($key, $value){
  133. return "$key => $value";
  134. }, array_keys($this->invokableAdapters), $this->invokableAdapters))
  135. );
  136. throw new Exception\InvalidArgumentException($message);
  137. } else {
  138. $adapterClass = $adapterAlias;
  139. }
  140. } else {
  141. $adapterClass = $this->invokableAdapters[$adapterAlias];
  142. }
  143. $dataOrAdapter = new $adapterClass($dataOrAdapter);
  144. }
  145. if (!($dataOrAdapter instanceof Adapter\AdapterInterface)) {
  146. $message = 'Data adapter "%s" is not instance of "Adapter\AdapterInterface"';
  147. $message = sprintf($message, get_class($dataOrAdapter));
  148. throw new Exception\InvalidArgumentException($message);
  149. }
  150. if ($dataOrAdapter instanceof DataGridAwareInterface) {
  151. $dataOrAdapter->setDataGrid($this);
  152. }
  153. if ($dataOrAdapter instanceof ListenerInterface) {
  154. $this->getEventManager()->attach($dataOrAdapter);
  155. }
  156. $this->adapter = $dataOrAdapter;
  157. $this->triggerEvent(GridEvent::EVENT_ADAPTER_SET);
  158. }
  159. public function getAdapter()
  160. {
  161. if (null !== $this->adapter) {
  162. return $this->adapter;
  163. }
  164. $message = 'Adapter is not set';
  165. throw new Exception\InvalidArgumentException($message);
  166. }
  167. public function setRenderer(Renderer\RendererInterface $renderer)
  168. {
  169. if ($renderer instanceof DataGridAwareInterface) {
  170. $renderer->setDataGrid($this);
  171. }
  172. if ($renderer instanceof ListenerInterface) {
  173. $this->getEventManager()->attach($renderer);
  174. }
  175. $this->renderer = $renderer;
  176. $this->triggerEvent(GridEvent::EVENT_RENDERER_SET);
  177. }
  178. public function getRenderer()
  179. {
  180. if (null !== $this->renderer) {
  181. return $this->renderer;
  182. }
  183. $message = 'Renderer is not set';
  184. throw new Exception\InvalidArgumentException($message);
  185. }
  186. public function toArray()
  187. {
  188. $this->triggerEvent(GridEvent::EVENT_EXECUTE);
  189. return $this->getAdapter()->toArray();
  190. }
  191. public function render()
  192. {
  193. $this->triggerEvent(GridEvent::EVENT_EXECUTE);
  194. return $this->triggerEvent(GridEvent::EVENT_RENDER)->last();
  195. }
  196. public function setSpecialColumn($columnName, $columnOptions)
  197. {
  198. $baseOptions = array(
  199. self::CELL => null,
  200. self::COLUMN => null,
  201. self::ACTIONS => null,
  202. );
  203. if (is_array($columnOptions))
  204. {
  205. $baseOptions = array_merge($baseOptions, $columnOptions);
  206. }
  207. elseif ($columnOptions instanceof \Closure)
  208. {
  209. $baseOptions[self::CELL] = $columnOptions;
  210. }
  211. $this->specialColumns[$columnName] = $baseOptions;
  212. }
  213. public function setSpecialColumns(array $specialColumns)
  214. {
  215. $this->specialColumns = array();
  216. foreach ($specialColumns as $name => $options) {
  217. $this->setSpecialColumn($name, $options);
  218. }
  219. }
  220. public function getSpecialColumns()
  221. {
  222. return $this->specialColumns;
  223. }
  224. public function getSpecialColumnsByType($type)
  225. {
  226. switch($type)
  227. {
  228. case self::CELL:
  229. return array_map(function($item) {
  230. return $item[DataGrid::CELL];
  231. }, $this->getSpecialColumns());
  232. case self::COLUMN:
  233. return array_map(function($item) {
  234. return $item[DataGrid::COLUMN];
  235. }, $this->getSpecialColumns());
  236. default:
  237. $message = sprintf('Undefined type "%s"', $type);
  238. throw new Exception\InvalidArgumentException($message);
  239. }
  240. }
  241. /**
  242. * @param \DataGrid\EventManager\EventManagerInterface $eventManager
  243. */
  244. public function setEventManager(EventManagerInterface $eventManager)
  245. {
  246. $this->eventManager = $eventManager;
  247. }
  248. /**
  249. * @return \DataGrid\EventManager\EventManagerInterface
  250. */
  251. public function getEventManager()
  252. {
  253. if (null === $this->eventManager) {
  254. $this->eventManager = new EventManager();
  255. $this->registerDefaultListeners();
  256. }
  257. return $this->eventManager;
  258. }
  259. /**
  260. * Set event listeners collection
  261. *
  262. * @param ListenerInterface[] $listeners
  263. * @throws Exception\InvalidArgumentException when listener in collection is not instance of DataGrid\EventManager\ListenerInterface
  264. */
  265. public function setListeners(array $listeners)
  266. {
  267. $em = $this->getEventManager();
  268. foreach ($listeners as $listener) {
  269. if ($listener instanceof ListenerInterface) {
  270. $em->attach($listener);
  271. } else {
  272. $message = 'Listener is not instance of "DataGrid\EventManager\ListenerInterface"';
  273. throw new Exception\InvalidArgumentException($message);
  274. }
  275. }
  276. }
  277. public function registerDefaultListeners()
  278. {
  279. // $this->eventManager->attach(
  280. // GridEvent::EVENT_EXECUTE,
  281. // function($e) {
  282. // $filterEvent = new Event\AdapterEvent('action');
  283. // $filterEvent->setAction('');
  284. //
  285. // /** @var $e \DataGrid\EventManager\GridEvent */
  286. // $em = $e->getDataGrid()->getEventManager();
  287. // $em->trigger();
  288. // }
  289. // );
  290. }
  291. /**
  292. * @param \DataGrid\StateStorage\StateStorageInterface $stateStorage
  293. */
  294. public function setStateStorage(StateStorageInterface $stateStorage)
  295. {
  296. if ($stateStorage instanceof DataGridAwareInterface) {
  297. $stateStorage->setDataGrid($this);
  298. }
  299. $this->stateStorage = $stateStorage;
  300. $this->triggerEvent(GridEvent::EVENT_STATE_STORAGE_SET);
  301. }
  302. /**
  303. * @return \DataGrid\StateStorage\StateStorageInterface
  304. */
  305. public function getStateStorage()
  306. {
  307. if (null === $this->stateStorage) {
  308. $this->setStateStorage(new Get());
  309. }
  310. return $this->stateStorage;
  311. }
  312. /**
  313. * Trigger grid event $name.
  314. *
  315. * @param string $name
  316. * @return ResultInterface
  317. */
  318. protected function triggerEvent($name)
  319. {
  320. $e = new GridEvent($name, $this);
  321. return $this->getEventManager()->trigger($e);
  322. }
  323. }