1: <?php
2:
3: namespace Charcoal\Ui\Dashboard;
4:
5: use InvalidArgumentException;
6:
7: // From 'charcoal-user'
8: use Charcoal\User\AuthAwareInterface;
9:
10: // From 'charcoal-ui'
11: use Charcoal\Ui\UiItemInterface;
12:
13: /**
14: * Provides an implementation of {@see \Charcoal\Ui\Dashboard\DashboardInterface}.
15: */
16: trait DashboardTrait
17: {
18: /**
19: * A colletion of widgets.
20: *
21: * @var UiItemInterface[]
22: */
23: private $widgets;
24:
25: /**
26: * Store a widget builder instance.
27: *
28: * @var object
29: */
30: protected $widgetBuilder;
31:
32: /**
33: * A callback applied to each widget output by {@see self::widgets()}.
34: *
35: * @var callable
36: */
37: private $widgetCallback;
38:
39: /**
40: * Set a widget builder.
41: *
42: * @param object $builder The builder to create customized widget objects.
43: * @throws InvalidArgumentException If the argument is not a widget builder.
44: * @return DashboardInterface Chainable
45: */
46: protected function setWidgetBuilder($builder)
47: {
48: if (is_object($builder)) {
49: $this->widgetBuilder = $builder;
50: } else {
51: throw new InvalidArgumentException(
52: sprintf(
53: 'Argument must be a widget builder, %s given',
54: (is_object($builder) ? get_class($builder) : gettype($builder))
55: )
56: );
57: }
58:
59: return $this;
60: }
61:
62: /**
63: * Set a callback to be applied to each widget output by {@see self::widgets()}.
64: *
65: * @param callable|null $callable A callback to be applied to each widget
66: * or NULL to disable the callback.
67: * @throws InvalidArgumentException If the argument is not callable or NULL.
68: * @return DashboardInterface Chainable
69: */
70: public function setWidgetCallback($callable)
71: {
72: if ($callable === null) {
73: $this->widgetCallback = null;
74:
75: return $this;
76: }
77:
78: if (is_callable($callable)) {
79: $this->widgetCallback = $callable;
80: } else {
81: throw new InvalidArgumentException(
82: sprintf(
83: 'Argument must be callable or NULL, %s given',
84: (is_object($callable) ? get_class($callable) : gettype($callable))
85: )
86: );
87: }
88:
89: return $this;
90: }
91:
92: /**
93: * Set the dashboard's widgets.
94: *
95: * @param array $widgets A collection of widgets.
96: * @return DashboardInterface Chainable
97: */
98: public function setWidgets(array $widgets)
99: {
100: $this->widgets = [];
101:
102: foreach ($widgets as $widgetIdent => $widget) {
103: $this->addWidget($widgetIdent, $widget);
104: }
105:
106: return $this;
107: }
108:
109: /**
110: * Add a widget to the dashboard.
111: *
112: * If a widget with the same $widgetIdent already exists, it will be overridden.
113: *
114: * @param string $widgetIdent The widget identifier.
115: * @param UiItemInterface|array $widget The widget object or structure.
116: * @throws InvalidArgumentException If the widget is invalid.
117: * @return DashboardInterface Chainable
118: */
119: public function addWidget($widgetIdent, $widget)
120: {
121: if (!is_string($widgetIdent)) {
122: throw new InvalidArgumentException(
123: 'Widget identifier needs to be a string'
124: );
125: }
126:
127: if ($widget instanceof UiItemInterface) {
128: $this->widgets[$widgetIdent] = $widget;
129: } elseif (is_array($widget)) {
130: if (!isset($widget['ident'])) {
131: $widget['ident'] = $widgetIdent;
132: }
133:
134: $w = $this->widgetBuilder->build($widget);
135:
136: $this->widgets[$widgetIdent] = $w;
137: } else {
138: throw new InvalidArgumentException(
139: 'Can not add widget: Invalid Widget.'
140: );
141: }
142:
143: return $this;
144: }
145:
146: /**
147: * Retrieve the dashboard's widgets.
148: *
149: * @param callable $widgetCallback A callback applied to each widget.
150: * @return UiItemInterface[]|Generator
151: */
152: public function widgets(callable $widgetCallback = null)
153: {
154: $widgets = $this->widgets;
155: uasort($widgets, [ $this, 'sortWidgetsByPriority' ]);
156:
157: $widgetCallback = isset($widgetCallback) ? $widgetCallback : $this->widgetCallback;
158: foreach ($widgets as $widget) {
159: if (isset($widget['permissions']) && $this instanceof AuthAwareInterface) {
160: $widget->setActive($this->hasPermissions($widget['permissions']));
161: }
162:
163: if (!$widget->active()) {
164: continue;
165: }
166:
167: if ($widgetCallback) {
168: $widgetCallback($widget);
169: }
170:
171: $GLOBALS['widget_template'] = $widget->template();
172:
173: yield $widget;
174:
175: $GLOBALS['widget_template'] = '';
176: }
177: }
178:
179: /**
180: * Determine if the dashboard has any widgets.
181: *
182: * @return boolean
183: */
184: public function hasWidgets()
185: {
186: return ($this->numWidgets() > 0);
187: }
188:
189: /**
190: * Count the number of widgets attached to the dashboard.
191: *
192: * @return integer
193: */
194: public function numWidgets()
195: {
196: return count($this->widgets);
197: }
198:
199: /**
200: * Static comparison function used by {@see uasort()}.
201: *
202: * @param mixed $a Widget A.
203: * @param mixed $b Widget B.
204: * @return integer Sorting value: -1 or 1
205: */
206: protected static function sortWidgetsByPriority($a, $b)
207: {
208: $a = $a->priority();
209: $b = $b->priority();
210:
211: return ($a < $b) ? (-1) : 1;
212: }
213: }
214: