Overview

Namespaces

  • Alpha
    • Controller
      • Front
    • Exception
    • Model
      • Type
    • Task
    • Util
      • Backup
      • Cache
      • Code
        • Highlight
        • Metric
      • Config
      • Convertor
      • Email
      • Extension
      • Feed
      • File
      • Graph
      • Helper
      • Http
        • Filter
        • Session
      • Image
      • Logging
      • Search
      • Security
    • View
      • Renderer
        • Html
        • Json
      • Widget

Classes

  • ActiveRecordController
  • ArticleController
  • AttachmentController
  • CacheController
  • Controller
  • DEnumController
  • ExcelController
  • FeedController
  • GenSecureQueryStringController
  • ImageController
  • IndexController
  • InstallController
  • ListActiveRecordsController
  • LogController
  • LoginController
  • LogoutController
  • MetricController
  • PhpinfoController
  • RecordSelectorController
  • SearchController
  • SequenceController
  • TagController

Interfaces

  • ControllerInterface
  • Overview
  • Namespace
  • Class
  • Tree
  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:  * Controller used to edit Tags related to the ActiveRecord indicated in the supplied
 26:  * GET vars (ActiveRecordType and ActiveRecordOID).  If no ActiveRecord Type or OID are
 27:  * indicated, then a screen to manage all tags at a summary level is presented.
 28:  *
 29:  * @since 1.0
 30:  *
 31:  * @author John Collins <dev@alphaframework.org>
 32:  * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
 33:  * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
 34:  * All rights reserved.
 35:  *
 36:  * <pre>
 37:  * Redistribution and use in source and binary forms, with or
 38:  * without modification, are permitted provided that the
 39:  * following conditions are met:
 40:  *
 41:  * * Redistributions of source code must retain the above
 42:  *   copyright notice, this list of conditions and the
 43:  *   following disclaimer.
 44:  * * Redistributions in binary form must reproduce the above
 45:  *   copyright notice, this list of conditions and the
 46:  *   following disclaimer in the documentation and/or other
 47:  *   materials provided with the distribution.
 48:  * * Neither the name of the Alpha Framework nor the names
 49:  *   of its contributors may be used to endorse or promote
 50:  *   products derived from this software without specific
 51:  *   prior written permission.
 52:  *
 53:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 54:  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 55:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 56:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 57:  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 58:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 59:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 60:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 61:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 62:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 63:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 64:  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 65:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 66:  * </pre>
 67:  */
 68: class TagController extends ActiveRecordController implements ControllerInterface
 69: {
 70:     /**
 71:      * Trace logger.
 72:      *
 73:      * @var Alpha\Util\Logging\Logger
 74:      *
 75:      * @since 1.0
 76:      */
 77:     private static $logger = null;
 78: 
 79:     /**
 80:      * constructor to set up the object.
 81:      *
 82:      * @since 1.0
 83:      */
 84:     public function __construct()
 85:     {
 86:         self::$logger = new Logger('TagController');
 87:         self::$logger->debug('>>__construct()');
 88: 
 89:         // ensure that the super class constructor is called, indicating the rights group
 90:         parent::__construct('Admin');
 91: 
 92:         // set up the title and meta details
 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:      * Handle GET requests.
102:      *
103:      * @param Alpha\Util\Http\Request $request
104:      *
105:      * @return Alpha\Util\Http\Response
106:      *
107:      * @throws Alpha\Exception\IllegalArguementException
108:      * @throws Alpha\Exception\FileNotFoundException
109:      *
110:      * @since 1.0
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:         // render the tag manager screen
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:             // render screen for managing individual tags on a given active record
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 .= '&nbsp;&nbsp;';
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:      * Handle POST requests.
281:      *
282:      * @param Alpha\Util\Http\Request $request
283:      *
284:      * @return Alpha\Util\Http\Response
285:      *
286:      * @throws Alpha\Exception\SecurityException
287:      * @throws Alpha\Exception\IllegalArguementException
288:      *
289:      * @since 1.0
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:             // check the hidden security fields before accepting the form POST data
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:                         // handle new tag if posted
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:                          * The unique key has most-likely been violated because this BO is already tagged with this
369:                          * value.
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:      * Handle DELETE requests.
407:      *
408:      * @param Alpha\Util\Http\Request $request
409:      *
410:      * @return Alpha\Util\Http\Response
411:      *
412:      * @throws Alpha\Exception\SecurityException
413:      * @throws Alpha\Exception\IllegalArguementException
414:      *
415:      * @since 2.0
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:      * Regenerates the tags on the supplied list of active records.
435:      *
436:      * @param array $records
437:      *
438:      * @since 1.0
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:                          * The unique key has most-likely been violated because this record is already tagged with this
451:                          * value, so we can ignore in this case.
452:                          */
453:                     }
454:                 }
455:             }
456:         }
457:     }
458: }
459: 
Alpha Framework 2.0.4 API Documentation API documentation generated by ApiGen 2.8.0