1: <?php
2:
3: namespace Alpha\Controller;
4:
5: use Alpha\Controller\Front\FrontController;
6: use Alpha\Util\Logging\Logger;
7: use Alpha\Util\Config\ConfigProvider;
8: use Alpha\Util\Http\Request;
9: use Alpha\Util\Http\Response;
10: use Alpha\Util\Helper\Validator;
11: use Alpha\View\View;
12: use Alpha\View\ViewState;
13: use Alpha\Exception\IllegalArguementException;
14: use Alpha\Exception\ResourceNotFoundException;
15: use Alpha\Exception\ResourceNotAllowedException;
16: use Alpha\Exception\SecurityException;
17: use Alpha\Exception\AlphaException;
18: use Alpha\Model\ActiveRecord;
19:
20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61:
62: class ActiveRecordController extends Controller implements ControllerInterface
63: {
64: 65: 66: 67: 68: 69: 70:
71: protected $start = 0;
72:
73: 74: 75: 76: 77: 78: 79:
80: protected $limit;
81:
82: 83: 84: 85: 86: 87: 88:
89: protected $recordCount = 0;
90:
91: 92: 93: 94: 95: 96: 97:
98: protected $sort;
99:
100: 101: 102: 103: 104: 105: 106:
107: protected $order;
108:
109: 110: 111: 112: 113: 114: 115:
116: protected $filterField;
117:
118: 119: 120: 121: 122: 123: 124:
125: protected $filterValue;
126:
127: 128: 129: 130: 131: 132: 133:
134: private static $logger = null;
135:
136: 137: 138: 139: 140: 141: 142:
143: public function __construct($visibility = 'Admin')
144: {
145: self::$logger = new Logger('ActiveRecordController');
146: self::$logger->debug('>>__construct()');
147:
148: $config = ConfigProvider::getInstance();
149:
150:
151: parent::__construct($visibility);
152:
153: self::$logger->debug('<<__construct');
154: }
155:
156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167:
168: public function doGET($request)
169: {
170: self::$logger->debug('>>doGET(request=['.var_export($request, true).'])');
171:
172: $config = ConfigProvider::getInstance();
173:
174: $params = $request->getParams();
175: $accept = $request->getAccept();
176:
177: $body = '';
178:
179: try {
180:
181: if (isset($params['ActiveRecordType']) && isset($params['ActiveRecordOID'])) {
182: if (!Validator::isInteger($params['ActiveRecordOID'])) {
183: throw new IllegalArguementException('Invalid oid ['.$params['ActiveRecordOID'].'] provided on the request!');
184: }
185:
186: $ActiveRecordType = urldecode($params['ActiveRecordType']);
187:
188: if (class_exists($ActiveRecordType)) {
189: $record = new $ActiveRecordType();
190: } else {
191: throw new IllegalArguementException('No ActiveRecord available to view!');
192: }
193:
194:
195: if (isset($params['view']) && $params['view'] == 'edit') {
196: if (!isset($this->title)) {
197: $this->setTitle('Editing a '.$record->getFriendlyClassName());
198: }
199: if (!isset($this->description)) {
200: $this->setDescription('Page to edit a '.$record->getFriendlyClassName().'.');
201: }
202: if (!isset($this->keywords)) {
203: $this->setKeywords('edit,'.$record->getFriendlyClassName());
204: }
205: } else {
206: if (!isset($this->title)) {
207: $this->setTitle('Viewing a '.$record->getFriendlyClassName());
208: }
209: if (!isset($this->description)) {
210: $this->setDescription('Page to view a '.$record->getFriendlyClassName().'.');
211: }
212: if (!isset($this->keywords)) {
213: $this->setKeywords('view,'.$record->getFriendlyClassName());
214: }
215: }
216:
217: $record->load($params['ActiveRecordOID']);
218: ActiveRecord::disconnect();
219:
220: $view = View::getInstance($record, false, $accept);
221:
222: $body .= View::displayPageHead($this);
223:
224: $message = $this->getStatusMessage();
225: if (!empty($message)) {
226: $body .= $message;
227: }
228:
229: $body .= View::renderDeleteForm($request->getURI());
230:
231: if (isset($params['view']) && $params['view'] == 'edit') {
232: $fields = array('formAction' => $this->request->getURI());
233: $body .= $view->editView($fields);
234: } else {
235: $body .= $view->detailedView();
236: }
237: } elseif (isset($params['ActiveRecordType']) && isset($params['start'])) {
238:
239: $ActiveRecordType = urldecode($params['ActiveRecordType']);
240:
241: if (class_exists($ActiveRecordType)) {
242: $record = new $ActiveRecordType();
243: } else {
244: throw new IllegalArguementException('No ActiveRecord available to view!');
245: }
246:
247:
248: if (!isset($this->title)) {
249: $this->setTitle('Listing all '.$record->getFriendlyClassName());
250: }
251: if (!isset($this->description)) {
252: $this->setDescription('Listing all '.$record->getFriendlyClassName());
253: }
254: if (!isset($this->keywords)) {
255: $this->setKeywords('list,all,'.$record->getFriendlyClassName());
256: }
257:
258: if (isset($this->filterField) && isset($this->filterValue)) {
259: if (isset($this->sort) && isset($this->order)) {
260: $records = $record->loadAllByAttribute($this->filterField, $this->filterValue, $params['start'], $params['limit'],
261: $this->sort, $this->order);
262: } else {
263: $records = $record->loadAllByAttribute($this->filterField, $this->filterValue, $params['start'], $params['limit']);
264: }
265:
266: $this->recordCount = $record->getCount(array($this->filterField), array($this->filterValue));
267: } else {
268: if (isset($this->sort) && isset($this->order)) {
269: $records = $record->loadAll($params['start'], $params['limit'], $this->sort, $this->order);
270: } else {
271: $records = $record->loadAll($params['start'], $params['limit']);
272: }
273:
274: $this->recordCount = $record->getCount();
275: }
276:
277: ActiveRecord::disconnect();
278:
279: $view = View::getInstance($record, false, $accept);
280:
281: $body .= View::displayPageHead($this);
282:
283: $message = $this->getStatusMessage();
284: if (!empty($message)) {
285: $body .= $message;
286: }
287:
288: $body .= View::renderDeleteForm($this->request->getURI());
289:
290: foreach ($records as $record) {
291: $view = View::getInstance($record, false, $accept);
292: $fields = array('formAction' => $this->request->getURI());
293: $body .= $view->listView($fields);
294: }
295:
296: if ($accept == 'application/json') {
297: $body = rtrim($body, ',');
298: }
299: } elseif (isset($params['ActiveRecordType'])) {
300:
301: $ActiveRecordType = urldecode($params['ActiveRecordType']);
302:
303: if (class_exists($ActiveRecordType)) {
304: $record = new $ActiveRecordType();
305: } else {
306: throw new IllegalArguementException('No ActiveRecord available to create!');
307: }
308:
309:
310: if (!isset($this->title)) {
311: $this->setTitle('Create a new '.$record->getFriendlyClassName());
312: }
313: if (!isset($this->description)) {
314: $this->setDescription('Create a new '.$record->getFriendlyClassName().'.');
315: }
316: if (!isset($this->keywords)) {
317: $this->setKeywords('create,new,'.$record->getFriendlyClassName());
318: }
319:
320: $view = View::getInstance($record, false, $accept);
321:
322: $body .= View::displayPageHead($this);
323: $fields = array('formAction' => $this->request->getURI());
324: $body .= $view->createView($fields);
325: } else {
326: throw new IllegalArguementException('No ActiveRecord available to display!');
327: }
328: } catch (IllegalArguementException $e) {
329: self::$logger->warn($e->getMessage());
330: throw new ResourceNotFoundException('The record that you have requested cannot be found!');
331: } catch (RecordNotFoundException $e) {
332: self::$logger->warn($e->getMessage());
333: throw new ResourceNotFoundException('The record that you have requested cannot be found!');
334: }
335:
336: $body .= View::displayPageFoot($this);
337:
338: self::$logger->debug('<<doGET');
339:
340: return new Response(200, $body, array('Content-Type' => ($accept == 'application/json' ? 'application/json' : 'text/html')));
341: }
342:
343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354:
355: public function doPOST($request)
356: {
357: self::$logger->debug('>>doDPOST(request=['.var_export($request, true).'])');
358:
359: $config = ConfigProvider::getInstance();
360:
361: $params = $request->getParams();
362: $accept = $request->getAccept();
363:
364: try {
365: if (isset($params['ActiveRecordType'])) {
366: $ActiveRecordType = urldecode($params['ActiveRecordType']);
367: } else {
368: throw new IllegalArguementException('No ActiveRecord available to create!');
369: }
370:
371: if (class_exists($ActiveRecordType)) {
372: $record = new $ActiveRecordType();
373: } else {
374: throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to create!');
375: }
376:
377:
378: if (!$this->checkSecurityFields()) {
379: throw new SecurityException('This page cannot accept post data from remote servers!');
380: }
381:
382: $record->populateFromArray($params);
383: $record->save();
384:
385: self::$logger->action('Created new '.$ActiveRecordType.' instance with OID '.$record->getOID());
386:
387: if (isset($params['statusMessage'])) {
388: $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
389: } else {
390: $this->setStatusMessage(View::displayUpdateMessage('Created'));
391: }
392:
393: ActiveRecord::disconnect();
394: } catch (SecurityException $e) {
395: self::$logger->warn($e->getMessage());
396: throw new ResourceNotAllowedException($e->getMessage());
397: } catch (IllegalArguementException $e) {
398: self::$logger->warn($e->getMessage());
399: throw new ResourceNotFoundException('The record that you have requested cannot be found!');
400: } catch (ValidationException $e) {
401: self::$logger->warn($e->getMessage().', query ['.$record->getLastQuery().']');
402: $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
403: }
404:
405: if ($accept == 'application/json') {
406: $view = View::getInstance($record, false, $accept);
407: $body = $view->detailedView();
408: $response = new Response(201);
409: $response->setHeader('Content-Type', 'application/json');
410: $response->setHeader('Location', $config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
411: $response->setBody($body);
412: } else {
413: $response = new Response(301);
414:
415: if ($this->getNextJob() != '') {
416: $response->redirect($this->getNextJob());
417: } else {
418: if ($this->request->isSecureURI()) {
419: $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.$ActiveRecordType.'&ActiveRecordOID='.$record->getOID()));
420: } else {
421: $response->redirect($config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
422: }
423: }
424: }
425:
426: self::$logger->debug('<<doPOST');
427:
428: return $response;
429: }
430:
431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442:
443: public function doPUT($request)
444: {
445: self::$logger->debug('>>doPUT(request=['.var_export($request, true).'])');
446:
447: $config = ConfigProvider::getInstance();
448:
449: $params = $request->getParams();
450: $accept = $request->getAccept();
451:
452: try {
453: if (isset($params['ActiveRecordType'])) {
454: $ActiveRecordType = urldecode($params['ActiveRecordType']);
455: } else {
456: throw new IllegalArguementException('No ActiveRecord available to edit!');
457: }
458:
459: if (class_exists($ActiveRecordType)) {
460: $record = new $ActiveRecordType();
461: } else {
462: throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to edit!');
463: }
464:
465:
466: if (!$this->checkSecurityFields()) {
467: throw new SecurityException('This page cannot accept post data from remote servers!');
468: }
469:
470: $record->load($params['ActiveRecordOID']);
471: $record->populateFromArray($params);
472: $record->save();
473:
474: self::$logger->action('Saved '.$ActiveRecordType.' instance with OID '.$record->getOID());
475:
476: if (isset($params['statusMessage'])) {
477: $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
478: } else {
479: $this->setStatusMessage(View::displayUpdateMessage('Saved'));
480: }
481:
482: ActiveRecord::disconnect();
483: } catch (SecurityException $e) {
484: self::$logger->warn($e->getMessage());
485: throw new ResourceNotAllowedException($e->getMessage());
486: } catch (IllegalArguementException $e) {
487: self::$logger->warn($e->getMessage());
488: throw new ResourceNotFoundException('The record that you have requested cannot be found!');
489: } catch (RecordNotFoundException $e) {
490: self::$logger->warn($e->getMessage());
491: throw new ResourceNotFoundException('The record that you have requested cannot be found!');
492: } catch (ValidationException $e) {
493: self::$logger->warn($e->getMessage().', query ['.$record->getLastQuery().']');
494: $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
495: }
496:
497: if ($accept == 'application/json') {
498: $view = View::getInstance($record, false, $accept);
499: $body = $view->detailedView();
500: $response = new Response(200);
501: $response->setHeader('Content-Type', 'application/json');
502: $response->setHeader('Location', $config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
503: $response->setBody($body);
504: } else {
505: $response = new Response(301);
506:
507: if ($this->getNextJob() != '') {
508: $response->redirect($this->getNextJob());
509: } else {
510: if ($this->request->isSecureURI()) {
511: $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.$ActiveRecordType.'&ActiveRecordOID='.$record->getOID().'&view=edit'));
512: } else {
513: $response->redirect($config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID().'/edit');
514: }
515: }
516: }
517:
518: self::$logger->debug('<<doPUT');
519:
520: return $response;
521: }
522:
523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534:
535: public function doDELETE($request)
536: {
537: self::$logger->debug('>>doDELETE(request=['.var_export($request, true).'])');
538:
539: $config = ConfigProvider::getInstance();
540:
541: $params = $request->getParams();
542: $accept = $request->getAccept();
543:
544: try {
545:
546: if (!$this->checkSecurityFields()) {
547: throw new SecurityException('This page cannot accept data from remote servers!');
548: }
549:
550: if (isset($params['ActiveRecordType'])) {
551: $ActiveRecordType = urldecode($params['ActiveRecordType']);
552: } else {
553: throw new IllegalArguementException('No ActiveRecord available to edit!');
554: }
555:
556: if (class_exists($ActiveRecordType)) {
557: $record = new $ActiveRecordType();
558: } else {
559: throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to edit!');
560: }
561:
562:
563: if (!$this->checkSecurityFields()) {
564: throw new SecurityException('This page cannot accept post data from remote servers!');
565: }
566:
567: $record->load($params['ActiveRecordOID']);
568:
569: ActiveRecord::begin();
570: $record->delete();
571: ActiveRecord::commit();
572: ActiveRecord::disconnect();
573:
574: self::$logger->action('Deleted '.$ActiveRecordType.' instance with OID '.$params['ActiveRecordOID']);
575:
576: if ($accept == 'application/json') {
577: $response = new Response(200);
578: $response->setHeader('Content-Type', 'application/json');
579: $response->setBody(json_encode(array('message' => 'deleted')));
580: } else {
581: $response = new Response(301);
582:
583: if (isset($params['statusMessage'])) {
584: $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
585: } else {
586: $this->setStatusMessage(View::displayUpdateMessage('Deleted'));
587: }
588:
589: if ($this->getNextJob() != '') {
590: $response->redirect($this->getNextJob());
591: } else {
592: if ($this->request->isSecureURI()) {
593: $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.$ActiveRecordType.'&start=0&limit='.$config->get('app.list.page.amount')));
594: } else {
595: $response->redirect($config->get('app.url').'/records/'.$params['ActiveRecordType']);
596: }
597: }
598: }
599: } catch (SecurityException $e) {
600: self::$logger->warn($e->getMessage());
601: throw new ResourceNotAllowedException($e->getMessage());
602: } catch (RecordNotFoundException $e) {
603: self::$logger->warn($e->getMessage());
604: throw new ResourceNotFoundException('The item that you have requested cannot be found!');
605: } catch (AlphaException $e) {
606: self::$logger->error($e->getMessage());
607: ActiveRecord::rollback();
608: }
609:
610: self::$logger->debug('<<doDELETE');
611:
612: return $response;
613: }
614:
615: 616: 617: 618: 619:
620: public function after_displayPageHead_callback()
621: {
622: $body = parent::after_displayPageHead_callback();
623:
624:
625: if ($this->request->getParam('start') != null) {
626: $this->start = $this->request->getParam('start');
627:
628: $viewState = ViewState::getInstance();
629: $viewState->set('selectedStart', $this->start);
630:
631: if ($this->request->getParam('limit') != null) {
632: $this->limit = $this->request->getParam('limit');
633: } else {
634: $config = ConfigProvider::getInstance();
635: $this->limit = $config->get('app.list.page.amount');
636: }
637:
638: $accept = $this->request->getAccept();
639:
640: if ($accept == 'application/json') {
641: $body .= '[';
642: }
643: }
644:
645: return $body;
646: }
647:
648: 649: 650: 651: 652: 653: 654:
655: public function ()
656: {
657: $body = '';
658:
659: if ($this->request->getParam('start') != null) {
660: $accept = $this->request->getAccept();
661:
662: if ($accept == 'application/json') {
663: $body .= ']';
664: } else {
665: $body .= $this->renderPageLinks();
666: $body .= '<br>';
667: }
668: }
669:
670: return $body;
671: }
672:
673: 674: 675: 676: 677: 678: 679:
680: protected function renderPageLinks()
681: {
682: $config = ConfigProvider::getInstance();
683:
684: $body = '';
685:
686:
687: $last = $this->start + $config->get('app.list.page.amount');
688:
689:
690: if ($last > $this->recordCount) {
691: $last = $this->recordCount;
692: }
693:
694:
695: if ($this->recordCount > 0) {
696: $body .= '<ul class="pagination">';
697: } else {
698: $body .= '<p align="center">The list is empty. </p>';
699:
700: return $body;
701: }
702:
703:
704: if ($this->start > 0) {
705:
706: if ($this->request->getParam('token', null) != null) {
707: $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.($this->start - $this->limit).'&limit='.$this->limit).'"><<-Previous</a></li>';
708: } else {
709: $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.($this->start - $this->limit).'/'.$this->limit.'"><<-Previous</a></li>';
710: }
711: } elseif ($this->recordCount > $this->limit) {
712: $body .= '<li class="disabled"><a href="#"><<-Previous</a></li>';
713: }
714:
715:
716: if ($this->recordCount > $this->limit) {
717: $page = 1;
718:
719: for ($i = 0; $i < $this->recordCount; $i += $this->limit) {
720: if ($i != $this->start) {
721:
722: if ($this->request->getParam('token', null) != null) {
723: $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.$i.'&limit='.$this->limit).'">'.$page.'</a></li>';
724: } else {
725: $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.$i.'/'.$this->limit.'">'.$page.'</a></li>';
726: }
727: } elseif ($this->recordCount > $this->limit) {
728: $body .= '<li class="active"><a href="#">'.$page.'</a></li>';
729: }
730:
731: ++$page;
732: }
733: }
734:
735:
736: if ($this->recordCount > $last) {
737:
738: if ($this->request->getParam('token', null) != null) {
739: $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.($this->start + $this->limit).'&limit='.$this->limit).'">Next->></a></li>';
740: } else {
741: $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.($this->start + $this->limit.'/'.$this->limit).
742: '">Next->></a></li>';
743: }
744: } elseif ($this->recordCount > $this->limit) {
745: $body .= '<li class="disabled"><a href="#">Next->></a></li>';
746: }
747:
748: $body .= '</ul>';
749:
750: return $body;
751: }
752: }
753: