1: <?php
2:
3: namespace Alpha\Controller;
4:
5: use Alpha\Util\Logging\Logger;
6: use Alpha\Util\Config\ConfigProvider;
7: use Alpha\Util\Security\SecurityUtils;
8: use Alpha\Util\Http\Response;
9: use Alpha\View\View;
10: use Alpha\View\Widget\StringBox;
11: use Alpha\View\Widget\Button;
12: use Alpha\Model\Tag;
13: use Alpha\Model\ActiveRecord;
14: use Alpha\Model\Type\String;
15: use Alpha\Controller\Front\FrontController;
16: use Alpha\Exception\IllegalArguementException;
17: use Alpha\Exception\SecurityException;
18: use Alpha\Exception\FileNotFoundException;
19: use Alpha\Exception\RecordNotFoundException;
20: use Alpha\Exception\ValidationException;
21: use Alpha\Exception\FailedSaveException;
22: use Alpha\Exception\AlphaException;
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: 63: 64: 65: 66: 67:
68: class TagController extends ActiveRecordController implements ControllerInterface
69: {
70: 71: 72: 73: 74: 75: 76:
77: private static $logger = null;
78:
79: 80: 81: 82: 83:
84: public function __construct()
85: {
86: self::$logger = new Logger('TagController');
87: self::$logger->debug('>>__construct()');
88:
89:
90: parent::__construct('Admin');
91:
92:
93: $this->setTitle('Editing Tags');
94: $this->setDescription('Page to edit tags.');
95: $this->setKeywords('edit,tags');
96:
97: self::$logger->debug('<<__construct');
98: }
99:
100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111:
112: public function doGET($request)
113: {
114: self::$logger->debug('>>doGET($request=['.var_export($request, true).'])');
115:
116: $params = $request->getParams();
117:
118: $config = ConfigProvider::getInstance();
119:
120: $body = '';
121:
122:
123: if (!isset($params['ActiveRecordType']) && !isset($params['ActiveRecordOID'])) {
124: $body .= View::displayPageHead($this);
125:
126: $message = $this->getStatusMessage();
127: if (!empty($message)) {
128: $body .= $message;
129: }
130:
131: $body .= '<h3>Listing active record which are tagged</h3>';
132: $ActiveRecordTypes = ActiveRecord::getBOClassNames();
133:
134: foreach ($ActiveRecordTypes as $ActiveRecordType) {
135: $record = new $ActiveRecordType();
136:
137: if ($record->isTagged()) {
138: $tag = new Tag();
139: $count = count($tag->loadAllByAttribute('taggedClass', $ActiveRecordType));
140: $body .= '<h4>'.$record->getFriendlyClassName().' record type is tagged ('.$count.' tags found)</h4>';
141: $fieldname = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('clearTaggedClass')) : 'clearTaggedClass');
142: $js = "if(window.jQuery) {
143: BootstrapDialog.show({
144: title: 'Confirmation',
145: message: 'Are you sure you want to delete all tags attached to the ".$record->getFriendlyClassName()." class, and have them re-created?',
146: buttons: [
147: {
148: icon: 'glyphicon glyphicon-remove',
149: label: 'Cancel',
150: cssClass: 'btn btn-default btn-xs',
151: action: function(dialogItself){
152: dialogItself.close();
153: }
154: },
155: {
156: icon: 'glyphicon glyphicon-ok',
157: label: 'Okay',
158: cssClass: 'btn btn-default btn-xs',
159: action: function(dialogItself) {
160: $('[id=\"".$fieldname."\"]').attr('value', '".addslashes($ActiveRecordType)."');
161: $('#clearForm').submit();
162: dialogItself.close();
163: }
164: }
165: ]
166: });
167: }";
168: $button = new Button($js, 'Re-create tags', 'clearBut'.stripslashes($ActiveRecordType));
169: $body .= $button->render();
170: }
171: }
172: ActiveRecord::disconnect();
173: $body .= '<form action="'.$request->getURI().'" method="POST" id="clearForm">';
174: $body .= '<input type="hidden" name="'.$fieldname.'" id="'.$fieldname.'"/>';
175: $body .= View::renderSecurityFields();
176: $body .= '</form>';
177: } elseif (isset($params['ActiveRecordType']) && $params['ActiveRecordType'] != 'Alpha\Model\Tag' && isset($params['ActiveRecordOID'])) {
178:
179:
180:
181: $body .= View::displayPageHead($this);
182:
183: $message = $this->getStatusMessage();
184: if (!empty($message)) {
185: $body .= $message;
186: }
187:
188: $ActiveRecordType = urldecode($params['ActiveRecordType']);
189: $ActiveRecordOID = $params['ActiveRecordOID'];
190:
191: if (class_exists($ActiveRecordType)) {
192: $record = new $ActiveRecordType();
193: } else {
194: throw new IllegalArguementException('No ActiveRecord available to display tags for!');
195: }
196:
197: try {
198: $record->load($ActiveRecordOID);
199:
200: $tags = $record->getPropObject('tags')->getRelatedObjects();
201:
202: ActiveRecord::disconnect();
203:
204: $body .= '<form action="'.$request->getURI().'" method="POST" accept-charset="UTF-8">';
205: $body .= '<h3>The following tags were found:</h3>';
206:
207: foreach ($tags as $tag) {
208: $labels = $tag->getDataLabels();
209:
210: $temp = new StringBox($tag->getPropObject('content'), $labels['content'], 'content_'.$tag->getID(), '');
211: $body .= $temp->render(false);
212:
213: $js = "if(window.jQuery) {
214: BootstrapDialog.show({
215: title: 'Confirmation',
216: message: 'Are you sure you wish to delete this tag?',
217: buttons: [
218: {
219: icon: 'glyphicon glyphicon-remove',
220: label: 'Cancel',
221: cssClass: 'btn btn-default btn-xs',
222: action: function(dialogItself){
223: dialogItself.close();
224: }
225: },
226: {
227: icon: 'glyphicon glyphicon-ok',
228: label: 'Okay',
229: cssClass: 'btn btn-default btn-xs',
230: action: function(dialogItself) {
231: $('[id=\"".($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('ActiveRecordOID')) : 'ActiveRecordOID')."\"]').attr('value', '".$tag->getID()."');
232: $('#deleteForm').submit();
233: dialogItself.close();
234: }
235: }
236: ]
237: });
238: }";
239: $button = new Button($js, 'Delete', 'delete'.$tag->getID().'But');
240: $body .= $button->render();
241: }
242:
243: $body .= '<h3>Add a new tag:</h3>';
244:
245: $temp = new StringBox(new String(), 'New tag', 'NewTagValue', '');
246: $body .= $temp->render(false);
247:
248: $temp = new Button('submit', 'Save', 'saveBut');
249: $body .= $temp->render();
250: $body .= ' ';
251: if ($params['ActiveRecordType'] = 'Alpha\Model\Article') {
252: $temp = new Button("document.location = '".FrontController::generateSecureURL('act=Alpha\Controller\ArticleController&ActiveRecordType='.$params['ActiveRecordType'].'&ActiveRecordOID='.$params['ActiveRecordOID'].'&view=edit')."'", 'Back to record', 'cancelBut');
253: } else {
254: $temp = new Button("document.location = '".FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$params['ActiveRecordType'].'&ActiveRecordOID='.$params['ActiveRecordOID'].'&view=edit')."'", 'Back to record', 'cancelBut');
255: }
256: $body .= $temp->render();
257:
258: $body .= View::renderSecurityFields();
259:
260: $body .= '</form>';
261:
262: $body .= View::renderDeleteForm($request->getURI());
263: } catch (RecordNotFoundException $e) {
264: $msg = 'Unable to load the ActiveRecord of id ['.$params['ActiveRecordOID'].'], error was ['.$e->getMessage().']';
265: self::$logger->error($msg);
266: throw new FileNotFoundException($msg);
267: }
268: } else {
269: return parent::doGET($request);
270: }
271:
272: $body .= View::displayPageFoot($this);
273:
274: self::$logger->debug('<<doGET');
275:
276: return new Response(200, $body, array('Content-Type' => 'text/html'));
277: }
278:
279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290:
291: public function doPOST($request)
292: {
293: self::$logger->debug('>>doPOST($request=['.var_export($request, true).'])');
294:
295: $params = $request->getParams();
296:
297: try {
298:
299: if (!$this->checkSecurityFields()) {
300: throw new SecurityException('This page cannot accept post data from remote servers!');
301: }
302:
303: if (isset($params['clearTaggedClass']) && $params['clearTaggedClass'] != '') {
304: try {
305: self::$logger->info('About to start rebuilding the tags for the class ['.$params['clearTaggedClass'].']');
306: $startTime = microtime(true);
307: $record = new $params['clearTaggedClass']();
308: $records = $record->loadAll();
309: self::$logger->info('Loaded all of the active records (elapsed time ['.round(microtime(true) - $startTime, 5).'] seconds)');
310: ActiveRecord::begin();
311: $tag = new Tag();
312: $tag->deleteAllByAttribute('taggedClass', $params['clearTaggedClass']);
313: self::$logger->info('Deleted all of the old tags (elapsed time ['.round(microtime(true) - $startTime, 5).'] seconds)');
314: $this->regenerateTagsOnRecords($records);
315: self::$logger->info('Saved all of the new tags (elapsed time ['.round(microtime(true) - $startTime, 5).'] seconds)');
316: self::$logger->action('Tags recreated on the ['.$params['clearTaggedClass'].'] class');
317: ActiveRecord::commit();
318: $this->setStatusMessage(View::displayUpdateMessage('Tags recreated on the '.$record->getFriendlyClassName().' class.'));
319: self::$logger->info('Tags recreated on the ['.$params['clearTaggedClass'].'] class (time taken ['.round(microtime(true) - $startTime, 5).'] seconds).');
320: } catch (AlphaException $e) {
321: self::$logger->error($e->getMessage());
322: ActiveRecord::rollback();
323: }
324: ActiveRecord::disconnect();
325:
326: return $this->doGET($request);
327: } elseif (isset($params['ActiveRecordType']) && isset($params['ActiveRecordOID'])) {
328: $ActiveRecordType = urldecode($params['ActiveRecordType']);
329: $ActiveRecordOID = $params['ActiveRecordOID'];
330:
331: if (class_exists($ActiveRecordType)) {
332: $record = new $ActiveRecordType();
333: } else {
334: throw new IllegalArguementException('No ActiveRecord available to display tags for!');
335: }
336:
337: if (isset($params['saveBut'])) {
338: try {
339: $record->load($ActiveRecordOID);
340:
341: $tags = $record->getPropObject('tags')->getRelatedObjects();
342:
343: ActiveRecord::begin();
344:
345: foreach ($tags as $tag) {
346: $tag->set('content', Tag::cleanTagContent($params['content_'.$tag->getID()]));
347: $tag->save();
348: self::$logger->action('Saved tag '.$tag->get('content').' on '.$ActiveRecordType.' instance with OID '.$ActiveRecordOID);
349: }
350:
351:
352: if (isset($params['NewTagValue']) && trim($params['NewTagValue']) != '') {
353: $newTag = new Tag();
354: $newTag->set('content', Tag::cleanTagContent($params['NewTagValue']));
355: $newTag->set('taggedOID', $ActiveRecordOID);
356: $newTag->set('taggedClass', $ActiveRecordType);
357: $newTag->save();
358: self::$logger->action('Created a new tag '.$newTag->get('content').' on '.$ActiveRecordType.' instance with OID '.$ActiveRecordOID);
359: }
360:
361: ActiveRecord::commit();
362:
363: $this->setStatusMessage(View::displayUpdateMessage('Tags on '.get_class($record).' '.$record->getID().' saved successfully.'));
364:
365: return $this->doGET($request);
366: } catch (ValidationException $e) {
367: 368: 369: 370:
371: ActiveRecord::rollback();
372:
373: $this->setStatusMessage(View::displayErrorMessage('Tags on '.get_class($record).' '.$record->getID().' not saved due to duplicate tag values, please try again.'));
374:
375: return $this->doGET($request);
376: } catch (FailedSaveException $e) {
377: self::$logger->error('Unable to save the tags of id ['.$params['ActiveRecordOID'].'], error was ['.$e->getMessage().']');
378: ActiveRecord::rollback();
379:
380: $this->setStatusMessage(View::displayErrorMessage('Tags on '.get_class($record).' '.$record->getID().' not saved, please check the application logs.'));
381:
382: return $this->doGET($request);
383: }
384:
385: ActiveRecord::disconnect();
386: }
387: } else {
388: return parent::doPOST($request);
389: }
390: } catch (SecurityException $e) {
391: $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
392:
393: self::$logger->warn($e->getMessage());
394: } catch (IllegalArguementException $e) {
395: self::$logger->error($e->getMessage());
396: } catch (RecordNotFoundException $e) {
397: self::$logger->warn($e->getMessage());
398:
399: $this->setStatusMessage(View::displayErrorMessage('Failed to load the requested item from the database!'));
400: }
401:
402: self::$logger->debug('<<doPOST');
403: }
404:
405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416:
417: public function doDELETE($request)
418: {
419: self::$logger->debug('>>doDELETE($request=['.var_export($request, true).'])');
420:
421: $config = ConfigProvider::getInstance();
422:
423: $this->setName($config->get('app.url').$this->request->getURI());
424: $this->setUnitOfWork(array($config->get('app.url').$this->request->getURI(), $config->get('app.url').$this->request->getURI()));
425:
426: $request->addParams(array('ActiveRecordType' => 'Alpha\Model\Tag'));
427:
428: self::$logger->debug('<<doDELETE');
429:
430: return parent::doDELETE($request);
431: }
432:
433: 434: 435: 436: 437: 438: 439:
440: private function regenerateTagsOnRecords($records)
441: {
442: foreach ($records as $record) {
443: foreach ($record->get('taggedAttributes') as $tagged) {
444: $tags = Tag::tokenize($record->get($tagged), get_class($record), $record->getOID());
445: foreach ($tags as $tag) {
446: try {
447: $tag->save();
448: } catch (ValidationException $e) {
449: 450: 451: 452:
453: }
454: }
455: }
456: }
457: }
458: }
459: