PageRenderTime 67ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/backend/widgets/ReportContainer.php

https://gitlab.com/gideonmarked/wellmarketing
PHP | 442 lines | 280 code | 83 blank | 79 comment | 22 complexity | 8d5fd1a91c811f046b96dbdc780c4a8e MD5 | raw file
  1. <?php namespace Backend\Widgets;
  2. use File;
  3. use Lang;
  4. use Request;
  5. use Backend\Classes\WidgetBase;
  6. use Backend\Classes\WidgetManager;
  7. use Backend\Models\UserPreferences;
  8. use ApplicationException;
  9. /**
  10. * Report Container Widget
  11. * Creates an area hosting report widgets.
  12. *
  13. * @package october\backend
  14. * @author Alexey Bobkov, Samuel Georges
  15. */
  16. class ReportContainer extends WidgetBase
  17. {
  18. //
  19. // Configurable properties
  20. //
  21. /**
  22. * @var string The unique report context name
  23. * Defines the context where the container is used.
  24. * Widget settings are saved in a specific context. This allows to
  25. * have multiple report containers on different pages that have
  26. * different widgets and widget settings. Context names can contain
  27. * only Latin letters.
  28. */
  29. public $context = 'dashboard';
  30. /**
  31. * @var string Determines whether widgets could be added and deleted.
  32. */
  33. public $canAddAndDelete = true;
  34. /**
  35. * @var array A list of default widgets to load.
  36. * This structure could be defined in the widget configuration file (for example config_report_container.yaml).
  37. * Example YAML structure:
  38. *
  39. * defaultWidgets:
  40. * trafficOverview:
  41. * class: RainLab\GoogleAnalytics\ReportWidgets\TrafficOverview
  42. * sortOrder: 1
  43. * configuration:
  44. * title: 'Traffic overview'
  45. * ocWidgetWidth: 10
  46. */
  47. public $defaultWidgets = [];
  48. //
  49. // Object properties
  50. //
  51. /**
  52. * {@inheritDoc}
  53. */
  54. protected $defaultAlias = 'reportContainer';
  55. /**
  56. * @var array Collection of all report widgets used by this container.
  57. */
  58. protected $reportWidgets = [];
  59. /**
  60. * @var boolean Determines if report widgets have been created.
  61. */
  62. protected $reportsDefined = false;
  63. /**
  64. * Constructor.
  65. */
  66. public function __construct($controller, $configuration = null)
  67. {
  68. if (!$configuration) {
  69. $configuration = 'config_report_container.yaml';
  70. }
  71. if (!is_array($configuration)) {
  72. $path = $controller->getConfigPath($configuration);
  73. if (File::isFile($path)) {
  74. $configuration = $this->makeConfig($path);
  75. }
  76. else {
  77. $configuration = [];
  78. }
  79. }
  80. parent::__construct($controller, $configuration);
  81. $this->bindToController();
  82. $this->fillFromConfig();
  83. }
  84. /**
  85. * Ensure report widgets are registered so they can also be bound to
  86. * the controller this allows their AJAX features to operate.
  87. * @return void
  88. */
  89. public function bindToController()
  90. {
  91. $this->defineReportWidgets();
  92. parent::bindToController();
  93. }
  94. /**
  95. * Renders this widget along with its collection of report widgets.
  96. */
  97. public function render()
  98. {
  99. $this->defineReportWidgets();
  100. $this->vars['widgets'] = $this->reportWidgets;
  101. return $this->makePartial('container');
  102. }
  103. /**
  104. * {@inheritDoc}
  105. */
  106. protected function loadAssets()
  107. {
  108. $this->addCss('css/reportcontainer.css', 'core');
  109. $this->addJs('vendor/isotope/jquery.isotope.min.js', 'core');
  110. $this->addJs('js/reportcontainer.js', 'core');
  111. }
  112. //
  113. // Event handlers
  114. //
  115. public function onUpdateWidget()
  116. {
  117. $alias = Request::input('alias');
  118. $widget = $this->findWidgetByAlias($alias);
  119. $this->saveWidgetProperties($alias, $widget->setProperties(
  120. json_decode(Request::input('fields'), true)
  121. ));
  122. return [
  123. '#'.$alias => $widget->render()
  124. ];
  125. }
  126. public function onRemoveWidget()
  127. {
  128. $alias = Request::input('alias');
  129. $this->removeWidget($alias);
  130. }
  131. public function onLoadAddPopup()
  132. {
  133. $sizes = [];
  134. for ($i = 1; $i <= 10; $i++) {
  135. $sizes[$i] = $i < 10 ? $i : $i.' (' . Lang::get('backend::lang.dashboard.full_width') . ')';
  136. }
  137. $this->vars['sizes'] = $sizes;
  138. $this->vars['widgets'] = WidgetManager::instance()->listReportWidgets();
  139. return $this->makePartial('new_widget_popup');
  140. }
  141. public function onAddWidget()
  142. {
  143. $className = trim(Request::input('className'));
  144. $size = trim(Request::input('size'));
  145. if (!$className) {
  146. throw new ApplicationException('Please select a widget to add.');
  147. }
  148. if (!class_exists($className)) {
  149. throw new ApplicationException('The selected class doesn\'t exist.');
  150. }
  151. $widget = new $className($this->controller);
  152. if (!($widget instanceof \Backend\Classes\ReportWidgetBase)) {
  153. throw new ApplicationException('The selected class is not a report widget.');
  154. }
  155. $widgetInfo = $this->addWidget($widget, $size);
  156. return [
  157. '@#'.$this->getId('container-list') => $this->makePartial('widget', [
  158. 'widget' => $widget,
  159. 'widgetAlias' => $widgetInfo['alias'],
  160. 'sortOrder' => $widgetInfo['sortOrder']
  161. ])
  162. ];
  163. }
  164. public function addWidget($widget, $size)
  165. {
  166. $widgets = $this->getWidgetsFromUserPreferences();
  167. $num = count($widgets);
  168. do {
  169. $num++;
  170. $alias = 'report_container_'.$this->context.'_'.$num;
  171. }
  172. while (array_key_exists($alias, $widgets));
  173. $sortOrder = 0;
  174. foreach ($widgets as $widgetInfo) {
  175. $sortOrder = max($sortOrder, $widgetInfo['sortOrder']);
  176. }
  177. $sortOrder++;
  178. $widget->setProperty('ocWidgetWidth', $size);
  179. $widgets[$alias] = [
  180. 'class' => get_class($widget),
  181. 'configuration' => $widget->getProperties(),
  182. 'sortOrder' => $sortOrder
  183. ];
  184. $this->setWidgetsToUserPreferences($widgets);
  185. return [
  186. 'alias' => $alias,
  187. 'sortOrder' => $widgets[$alias]['sortOrder']
  188. ];
  189. }
  190. public function onSetWidgetOrders()
  191. {
  192. $aliases = trim(Request::input('aliases'));
  193. $orders = trim(Request::input('orders'));
  194. if (!$aliases) {
  195. throw new ApplicationException('Invalid aliases string.');
  196. }
  197. if (!$orders) {
  198. throw new ApplicationException('Invalid orders string.');
  199. }
  200. $aliases = explode(',', $aliases);
  201. $orders = explode(',', $orders);
  202. if (count($aliases) != count($orders)) {
  203. throw new ApplicationException('Invalid data posted.');
  204. }
  205. $widgets = $this->getWidgetsFromUserPreferences();
  206. foreach ($aliases as $index => $alias) {
  207. if (isset($widgets[$alias])) {
  208. $widgets[$alias]['sortOrder'] = $orders[$index];
  209. }
  210. }
  211. $this->setWidgetsToUserPreferences($widgets);
  212. }
  213. //
  214. // Methods for the internal use
  215. //
  216. /**
  217. * Registers the report widgets that will be included in this container.
  218. * The chosen widgets are based on the user preferences.
  219. */
  220. protected function defineReportWidgets()
  221. {
  222. if ($this->reportsDefined) {
  223. return;
  224. }
  225. $result = [];
  226. $widgets = $this->getWidgetsFromUserPreferences();
  227. foreach ($widgets as $alias => $widgetInfo) {
  228. if ($widget = $this->makeReportWidget($alias, $widgetInfo)) {
  229. $result[$alias] = $widget;
  230. }
  231. }
  232. uasort($result, function ($a, $b) {
  233. return $a['sortOrder'] - $b['sortOrder'];
  234. });
  235. $this->reportWidgets = $result;
  236. $this->reportsDefined = true;
  237. }
  238. /**
  239. * Makes a single report widget object, returned array index:
  240. * - widget: The widget object (Backend\Classes\ReportWidgetBase)
  241. * - sortOrder: The current sort order
  242. *
  243. * @param string $alias
  244. * @param array $widgetInfo
  245. * @return array
  246. */
  247. protected function makeReportWidget($alias, $widgetInfo)
  248. {
  249. $configuration = $widgetInfo['configuration'];
  250. $configuration['alias'] = $alias;
  251. $className = $widgetInfo['class'];
  252. if (!class_exists($className)) {
  253. return;
  254. }
  255. $widget = new $className($this->controller, $configuration);
  256. $widget->bindToController();
  257. return ['widget' => $widget, 'sortOrder' => $widgetInfo['sortOrder']];
  258. }
  259. protected function getWidgetsFromUserPreferences()
  260. {
  261. $widgets = UserPreferences::forUser()
  262. ->get($this->getUserPreferencesKey(), $this->defaultWidgets);
  263. if (!is_array($widgets)) {
  264. return [];
  265. }
  266. return $widgets;
  267. }
  268. protected function setWidgetsToUserPreferences($widgets)
  269. {
  270. UserPreferences::forUser()->set($this->getUserPreferencesKey(), $widgets);
  271. }
  272. protected function saveWidgetProperties($alias, $properties)
  273. {
  274. $widgets = $this->getWidgetsFromUserPreferences();
  275. if (isset($widgets[$alias])) {
  276. $widgets[$alias]['configuration'] = $properties;
  277. $this->setWidgetsToUserPreferences($widgets);
  278. }
  279. }
  280. protected function removeWidget($alias)
  281. {
  282. $widgets = $this->getWidgetsFromUserPreferences();
  283. if (isset($widgets[$alias])) {
  284. unset($widgets[$alias]);
  285. }
  286. $this->setWidgetsToUserPreferences($widgets);
  287. }
  288. protected function findWidgetByAlias($alias)
  289. {
  290. $this->defineReportWidgets();
  291. $widgets = $this->reportWidgets;
  292. if (!isset($widgets[$alias])) {
  293. throw new ApplicationException('The specified widget is not found.');
  294. }
  295. return $widgets[$alias]['widget'];
  296. }
  297. protected function getWidgetPropertyConfig($widget)
  298. {
  299. $properties = $widget->defineProperties();
  300. $property = [
  301. 'property' => 'ocWidgetWidth',
  302. 'title' => Lang::get('backend::lang.dashboard.widget_columns_label', ['columns' => '(1-10)']),
  303. 'description' => Lang::get('backend::lang.dashboard.widget_columns_description'),
  304. 'type' => 'dropdown',
  305. 'validationPattern' => '^[0-9]+$',
  306. 'validationMessage' => Lang::get('backend::lang.dashboard.widget_columns_error'),
  307. 'options' => [
  308. 1 => '1 ' . Lang::choice('backend::lang.dashboard.columns', 1),
  309. 2 => '2 ' . Lang::choice('backend::lang.dashboard.columns', 2),
  310. 3 => '3 ' . Lang::choice('backend::lang.dashboard.columns', 3),
  311. 4 => '4 ' . Lang::choice('backend::lang.dashboard.columns', 4),
  312. 5 => '5 ' . Lang::choice('backend::lang.dashboard.columns', 5),
  313. 6 => '6 ' . Lang::choice('backend::lang.dashboard.columns', 6),
  314. 7 => '7 ' . Lang::choice('backend::lang.dashboard.columns', 7),
  315. 8 => '8 ' . Lang::choice('backend::lang.dashboard.columns', 8),
  316. 9 => '9 ' . Lang::choice('backend::lang.dashboard.columns', 9),
  317. 10 => '10 ' . Lang::choice('backend::lang.dashboard.columns', 10)
  318. ]
  319. ];
  320. $result[] = $property;
  321. $property = [
  322. 'property' => 'ocWidgetNewRow',
  323. 'title' => Lang::get('backend::lang.dashboard.widget_new_row_label'),
  324. 'description' => Lang::get('backend::lang.dashboard.widget_new_row_description'),
  325. 'type' => 'checkbox'
  326. ];
  327. $result[] = $property;
  328. foreach ($properties as $name => $params) {
  329. $property = [
  330. 'property' => $name,
  331. 'title' => isset($params['title']) ? Lang::get($params['title']) : $name,
  332. 'type' => isset($params['type']) ? $params['type'] : 'string'
  333. ];
  334. foreach ($params as $name => $value) {
  335. if (isset($property[$name])) {
  336. continue;
  337. }
  338. $property[$name] = !is_array($value) ? Lang::get($value) : $value;
  339. }
  340. $result[] = $property;
  341. }
  342. return json_encode($result);
  343. }
  344. protected function getWidgetPropertyValues($widget)
  345. {
  346. $result = [];
  347. $properties = $widget->defineProperties();
  348. foreach ($properties as $name => $params) {
  349. $result[$name] = Lang::get($widget->property($name));
  350. }
  351. $result['ocWidgetWidth'] = $widget->property('ocWidgetWidth');
  352. $result['ocWidgetNewRow'] = $widget->property('ocWidgetNewRow');
  353. return json_encode($result);
  354. }
  355. protected function getUserPreferencesKey()
  356. {
  357. return 'backend::reportwidgets.'.$this->context;
  358. }
  359. }