1: <?php
2:
3: App::uses('ArrayUtil', 'Base.Lib');
4: App::uses('AppHelper', 'View/Helper');
5: App::uses('ControllerInspector', 'Base.Lib');
6: App::uses('ActionListHelper', 'Widgets.View/Helper');
7:
8: 9: 10: 11:
12: class extends AppHelper {
13:
14: public $helpers = array(
15: 'Html',
16: 'AccessControl.AccessControl',
17: 'Base.CakeLayers',
18: 'Widgets.ActionList',
19: );
20:
21: 22: 23:
24: private $defaultActions = array(
25: array(
26: 'url' => array('action' => 'index'),
27: 'hasId' => false,
28: 'format' => 'Listar %s',
29: 'plural' => true
30: ),
31: array(
32: 'url' => array('action' => 'add'),
33: 'hasId' => false,
34: 'format' => 'Novo(a) %s',
35: 'plural' => false
36: ),
37: array('url' => array('action' => 'view'), 'hasId' => true, 'format' => 'Visualizar %s', 'plural' => false),
38: array('url' => array('action' => 'edit'), 'hasId' => true, 'format' => 'Editar %s', 'plural' => false),
39: array('url' => array('action' => 'delete'), 'hasId' => true, 'format' => 'Remover %s', 'plural' => false,
40: 'question' => 'Tem certeza de que deseja remover?', 'post' => true)
41: );
42:
43: 44: 45:
46: public $settings = array(
47: 'listLayoutBeforeAll' => '',
48: 'listLayoutAfterAll' => '',
49: 'listLayoutBeforeEach' => '',
50: 'listLayoutAfterEach' => '',
51: 'tableLayoutBeforeAll' => '',
52: 'tableLayoutAfterAll' => '',
53: 'tableLayoutBeforeEach' => '',
54: 'tableLayoutAfterEach' => '',
55: 'layout' => ActionListHelper::LAYOUT_LIST,
56: 'skipActions' => array(),
57: 'controller' => null,
58: 'id' => null,
59: 'debug' => false,
60: );
61:
62: 63: 64:
65: private = array(
66: 'shortFormat' => false,
67: 'skipNoRequiredIdActions' => false,
68: 'layout' => ActionListHelper::LAYOUT_LIST,
69: );
70:
71: 72: 73:
74: private = array(
75: 'shortFormat' => true,
76: 'skipNoRequiredIdActions' => true,
77: 'layout' => ActionListHelper::LAYOUT_TABLE,
78: );
79:
80: 81: 82: 83: 84:
85: public function ($options = array()) {
86: $options = $this->_buildOptions($this->moduleMenuDefaultOptions, $options);
87: return $this->_menuByOptions(
88: $options
89: );
90: }
91:
92: 93: 94: 95: 96: 97:
98: public function ($instance, $options = array()) {
99: $options = $this->_buildOptions($this->instanceMenuDefaultOptions, $options);
100: $options['id'] = $this->_getInstanceId($instance, $options);
101: return $this->_menuByOptions($options);
102: }
103:
104: 105: 106: 107: 108: 109:
110: private function _buildOptions($defaultOptions, $userOptions) {
111: $ret = array_merge($this->settings, $defaultOptions, $userOptions);
112: $ret['_currentController'] = $this->CakeLayers->getController($this->params['controller']);
113: $ret['_targetController'] = $this->CakeLayers->getController($ret['controller']);
114: $ret['_targetObjectModel'] = $ret['_targetController']->{$ret['_targetController']->modelClass};
115: return $ret;
116: }
117:
118: 119: 120: 121: 122:
123: private function ($options) {
124: $controllerActions = $this->_navigableActions(
125: $this->_moduleActions($options), $options
126: );
127: $actions = array();
128: foreach ($controllerActions as $controllerAction) {
129: $actions[] = array(
130: 'caption' => $this->_getTitle($controllerAction, $options),
131: 'post' => array_key_exists('post', $controllerAction) && $controllerAction['post'],
132: 'url' => $this->_buildActionUrl($controllerAction, $options),
133: 'question' => array_key_exists('question', $controllerAction) ? $controllerAction['question'] : false,
134: );
135: }
136: return $this->ActionList->actionList($actions, $options);
137: }
138:
139: 140: 141: 142: 143: 144:
145: private function _getInstanceId($instance, $options) {
146: if (empty($options['model'])) {
147: $model = $options['_targetController']->{
148: $options['_targetController']->modelClass
149: };
150: } else {
151: $model = $this->CakeLayers->getModel($options['model']);
152: }
153: return $instance[$model->alias][$model->primaryKey];
154: }
155:
156: private function _navigableActions($actions, $options) {
157: $navigableActions = array();
158: foreach ($actions as $action) {
159: if ($this->_isNavigable($action, $options)) {
160: $navigableActions[] = $action;
161: }
162: }
163: return $navigableActions;
164: }
165:
166: private function _moduleActions($options) {
167: $groups = array($this->defaultActions);
168: if (!empty($options['moduleActions'])) {
169: $groups[] = $options['moduleActions'];
170: }
171: if (!empty($options['_targetController']->moduleActions)) {
172: $groups[] = $options['_targetController']->moduleActions;
173: }
174:
175: $added = array();
176:
177: foreach ($groups as $group) {
178: foreach ($group as $action) {
179: $url = $this->_extractActionUrl($action, $options);
180: $actionPath = $url['controller'] . '/' . $url['action'];
181: $added[$actionPath] = $action;
182: }
183: }
184:
185: return $added;
186: }
187:
188: public function setDefaultOption($key, $value) {
189: $this->defaultOptions[$key] = $value;
190: }
191:
192: private function _isNavigable($targetAction, $options) {
193: $message = $this->_checkNavigable($targetAction, $options);
194: if ($message == false) {
195: return true;
196: } else {
197: if ($options['debug']) {
198: debug(array('notNavigable' => compact('message', 'targetAction')));
199: }
200:
201: return false;
202: }
203: }
204:
205: private function _checkNavigable($targetAction, $options) {
206: $actionUrl = $this->_extractActionUrl($targetAction, $options);
207:
208:
209: if (!$this->AccessControl->hasAccessByUrl($this->_buildActionUrl($targetAction, $options))) {
210: return __d('widgets','Access denied.');
211: }
212:
213: $currentUrl = $this->_extractCurrentUrl($options);
214:
215:
216: if (($currentUrl['controller'] == $actionUrl['controller']) &&
217: ($currentUrl['action'] == $actionUrl['action'])) {
218: return __d('widgets','Same controller/action.');
219: }
220:
221:
222: if ($options['shortFormat'] && !empty($targetAction['skipOnShort'])) {
223: return __d('widgets','Skip on short format menu.');
224: }
225:
226:
227: if ($targetAction['hasId'] && $actionUrl['id'] == null) {
228: return __d('widgets','Has not required id.');
229: }
230:
231:
232: if (!$targetAction['hasId'] && $options['skipNoRequiredIdActions']) {
233: return __d('widgets','Skip no required id actions.');
234: }
235:
236:
237: if ($this->_deniedAction($actionUrl, $options)) {
238: return __d('widgets','Denied by controller.');
239: }
240:
241:
242: foreach ($options['skipActions'] as $skipActionUrl) {
243: if ($this->_isUrlEquals($this->_parseUrl($skipActionUrl), $actionUrl)) {
244: return __d('widgets','Action skipped.');
245: }
246: }
247:
248:
249: if (!$this->_isNavigableControllerMethod($targetAction, $options)) {
250: return __d('widgets','Navigable method returned false.');
251: }
252:
253: return false;
254: }
255:
256: private function _deniedAction($actionUrl, $options) {
257: if ($actionUrl['controller'] == $this->_getTargetControllerUri($options)) {
258: return !ControllerInspector::actionExists($options['_targetController'], $actionUrl['action']) ||
259: (isset($options['_targetController']->notModuleActions) &&
260: array_search($actionUrl['action'], $options['_targetController']->notModuleActions) !== false);
261: } else {
262: return false;
263: }
264: }
265:
266: private function _buildActionUrl($targetAction, $options) {
267: $actionUrl = $this->_extractActionUrl($targetAction, $options);
268:
269: $url = '';
270:
271: if ($actionUrl['plugin']) {
272: $url .= "/{$actionUrl['plugin']}";
273: }
274:
275: $url .= "/{$actionUrl['controller']}/{$actionUrl['action']}";
276:
277: if ($targetAction['hasId']) {
278: if (isset($targetAction['namedParam']) && $targetAction['namedParam']) {
279: $url .= "/{$targetAction['namedParam']}:{$actionUrl['id']}";
280: } else {
281: $url .= "/{$actionUrl['id']}";
282: }
283: }
284: $current = Router::parse($this->request->url);
285: foreach($current['named'] as $key => $value) {
286: $url .= "/$key:$value";
287: }
288: return $url;
289: }
290:
291: private function _getTitle($action, $options) {
292: $actionUrl = $this->_extractActionUrl($action, $options);
293:
294: if ($options['shortFormat']) {
295: return trim(sprintf($action['format'], ''));
296: } else {
297: $title = Inflector::singularize($actionUrl['controller']);
298: $title = !empty($action['plural']) ? $actionUrl['controller'] : Inflector::singularize($actionUrl['controller']);
299: $title = Inflector::humanize($title);
300: $title = str_replace(' ', '', $title);
301: return trim(sprintf($action['format'], __d('widgets',$title)));
302: }
303: }
304:
305: private function ($options) {
306: $controller = $this->params['controller'];
307: $action = isset($this->params['action']) ? $this->params['action'] : 'index';
308: $id = isset($this->params['pass'][0]) ? $this->params['pass'][0] : null;
309:
310:
311: if ($action == 'add_or_edit') {
312: $action = empty($id) ? 'add' : 'edit';
313: }
314:
315: return array(
316: 'controller' => $controller,
317: 'action' => $action,
318: 'id' => ($options['id'] ? $options['id'] : $id )
319: );
320: }
321:
322: private function _getTargetControllerUri($options) {
323: return Inflector::underscore($options['_targetController']->name);
324: }
325:
326: private function _getTargetControllerPluginUri($options) {
327: return empty($options['_targetController']->plugin) ? null : Inflector::underscore($options['_targetController']->plugin);
328: }
329:
330: private function ($action, $options) {
331: $actionUrl = $this->_parseUrl($action['url']);
332: return array(
333: 'plugin' => $actionUrl['plugin'] ? $actionUrl['plugin'] : $this->_getTargetControllerPluginUri($options),
334: 'controller' => $actionUrl['controller'] ? $actionUrl['controller'] : $this->_getTargetControllerUri($options),
335: 'action' => isset($actionUrl['action']) ? $actionUrl['action'] : 'index',
336: 'id' => $this->_extractActionId($action, $options)
337: );
338: }
339:
340: private function _parseUrl($url) {
341: if (is_string($url)) {
342: $url = Router::parse($url);
343: }
344:
345: $url['plugin'] = isset($url['plugin']) ? $url['plugin'] : null;
346: $url['controller'] = isset($url['controller']) ? $url['controller'] : null;
347: $url['action'] = isset($url['action']) ? $url['action'] : 'index';
348:
349: return $url;
350: }
351:
352: private function ($action, $options) {
353: $currentUrl = $this->_extractCurrentUrl($options);
354:
355: if ($action['hasId']) {
356: if (isset($action['field']) && $action['field']) {
357: $obj = $this->_getTargetControllerObject($currentUrl['id'], $options);
358: $model = $options['_targetObjectModel'];
359: return $obj && $model ?
360: $this->_getObjectFieldValue($model->name, $obj, $action['field']) :
361: $this->_getCurrentActionFieldValue($action['field']);
362: } else {
363: return $currentUrl['id'];
364: }
365: } else {
366: return null;
367: }
368: }
369:
370: private function _getTargetControllerObject($primaryKeyValue, $options) {
371: $model = $options['_targetObjectModel'];
372: return $model->find(
373: 'first', array(
374: 'conditions' => array(
375: "{$model->name}.{$model->primaryKey}" => $primaryKeyValue
376: )
377: )
378: );
379: }
380:
381: private function _getObjectFieldValue($model, $object, $field) {
382: return $this->CakeLayers->modelInstanceField($model, $object, $field);
383: }
384:
385: private function _getCurrentActionFieldValue($field) {
386: $parts = explode('.', $field);
387: $underscoreParts = array();
388: foreach ($parts as $part) {
389: $underscoreParts[] = Inflector::underscore($part);
390: }
391: $field = implode('_', $underscoreParts);
392:
393: if (!empty($this->params['named'][$field])) {
394: return $this->params['named'][$field];
395: }
396: if (count($parts) == 1) {
397: $parts = array_merge(
398: $this->CakeLayers->getModel()->alias, $parts
399: );
400: }
401: if (ArrayUtil::hasArrayIndex($this->data, $parts)) {
402: return ArrayUtil::arrayIndex($this->data, $parts);
403: }
404:
405: return null;
406: }
407:
408: private function _isUrlEquals($url1, $url2) {
409: return $url1['controller'] == $url2['controller']
410: && $url1['action'] == $url2['action'];
411: }
412:
413: private function _isNavigableControllerMethod($targetAction, $options) {
414: $actionUrl = $this->_extractActionUrl($targetAction, $options);
415: $methodName = '__' . Inflector::variable("is_navigable_" . $actionUrl['action']);
416: $controller = $this->CakeLayers->getController($actionUrl['controller']);
417:
418: if (method_exists($controller, $methodName)) {
419: return call_user_func(array($controller, $methodName), array(
420: 'options' => $options,
421: 'currentUrl' => $this->_extractCurrentUrl($options),
422: 'targetAction' => $targetAction,
423: 'targetActionUrl' => $actionUrl,
424: ));
425: } else {
426: return true;
427: }
428: }
429:
430: }
431:
432: ?>
433: