TagController::doPOST()   F
last analyzed

Complexity

Conditions 17
Paths 1113

Size

Total Lines 111

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 111
rs 0.8399
cc 17
nc 1113
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\SmallTextBox;
11
use Alpha\View\Widget\Button;
12
use Alpha\Model\Tag;
13
use Alpha\Model\ActiveRecord;
14
use Alpha\Model\Type\SmallText;
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 ActiveRecordID).  If no ActiveRecord Type or ID 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 <[email protected]>
32
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
33
 * @copyright Copyright (c) 2019, 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;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
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
        $fields = array();
122
        $tagsHTML = '';
123
124
        // render the tag manager screen
125
        if (!isset($params['ActiveRecordType']) && !isset($params['ActiveRecordID'])) {
126
            $body .= View::displayPageHead($this);
127
128
            $message = $this->getStatusMessage();
129
            if (!empty($message)) {
130
                $body .= $message;
131
            }
132
133
            $ActiveRecordTypes = ActiveRecord::getRecordClassNames();
134
            $fieldname = '';
135
136
            foreach ($ActiveRecordTypes as $ActiveRecordType) {
137
                $record = new $ActiveRecordType();
138
139
                if ($record->isTagged()) {
140
                    $tag = new Tag();
141
                    $count = count($tag->loadAllByAttribute('taggedClass', $ActiveRecordType));
142
                    $fields['friendlyClassName'] = $record->getFriendlyClassName();
143
                    $fields['count'] = $count;
144
                    $fields['fieldname'] = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('clearTaggedClass')) : 'clearTaggedClass');
145
                    $fields['ActiveRecordType'] = $ActiveRecordType;
146
                    $fields['adminView'] = true;
147
148
                    $tagsHTML .= View::loadTemplateFragment('html', 'tagsadmin.phtml', $fields);
149
                }
150
            }
151
152
            ActiveRecord::disconnect();
153
            $fields = array();
154
            $fields['formAction'] = $request->getURI();
155
            $fields['fieldname'] = $fieldname;
156
            $fields['securityFields'] = View::renderSecurityFields();
157
            $fields['tagsHTML'] = $tagsHTML;
158
159
            $body .= View::loadTemplateFragment('html', 'tagslist.phtml', $fields);
160
        } elseif (isset($params['ActiveRecordType']) && $params['ActiveRecordType'] != 'Alpha\Model\Tag' && isset($params['ActiveRecordID'])) {
161
162
            // render screen for managing individual tags on a given active record
163
164
            $body .= View::displayPageHead($this);
165
166
            $message = $this->getStatusMessage();
167
            if (!empty($message)) {
168
                $body .= $message;
169
            }
170
171
            $ActiveRecordType = urldecode($params['ActiveRecordType']);
172
            $ActiveRecordID = $params['ActiveRecordID'];
173
174
            if (class_exists($ActiveRecordType)) {
175
                $record = new $ActiveRecordType();
176
            } else {
177
                throw new IllegalArguementException('No ActiveRecord available to display tags for!');
178
            }
179
180
            try {
181
                $record->load($ActiveRecordID);
182
183
                $tags = $record->getPropObject('tags')->getRelated();
184
185
                ActiveRecord::disconnect();
186
187
                foreach ($tags as $tag) {
188
                    $labels = $tag->getDataLabels();
189
190
                    $temp = new SmallTextBox($tag->getPropObject('content'), $labels['content'], 'content_'.$tag->getID(), '');
191
                    $fields['contentSmallTextBox'] = $temp->render(false);
192
                    $fields['fieldname'] = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('ActiveRecordID')) : 'ActiveRecordID');
193
                    $fields['tagID'] = $tag->getID();
194
                    $fields['adminView'] = false;
195
196
                    $tagsHTML .= View::loadTemplateFragment('html', 'tagsadmin.phtml', $fields);
197
                }
198
199
                $temp = new SmallTextBox(new SmallText(), 'New tag', 'NewTagValue', '');
200
                $fields['newTagValueTextBox'] = $temp->render(false);
201
202
                $temp = new Button('submit', 'Save', 'saveBut');
203
                $fields['saveButton'] = $temp->render();
204
205
                if ($params['ActiveRecordType'] = 'Alpha\Model\Article') {
206
                    $temp = new Button("document.location = '".FrontController::generateSecureURL('act=Alpha\Controller\ArticleController&ActiveRecordType='.$params['ActiveRecordType'].'&ActiveRecordID='.$params['ActiveRecordID'].'&view=edit')."'", 'Back to record', 'cancelBut');
207
                } else {
208
                    $temp = new Button("document.location = '".FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$params['ActiveRecordType'].'&ActiveRecordID='.$params['ActiveRecordID'].'&view=edit')."'", 'Back to record', 'cancelBut');
209
                }
210
                $fields['cancelButton'] = $temp->render();
211
212
                $fields['securityFields'] = View::renderSecurityFields();
213
                $fields['deleteForm'] = View::renderDeleteForm($request->getURI());
214
                $fields['formAction'] = $request->getURI();
215
                $fields['tagsHTML'] = $tagsHTML;
216
217
                $body .= View::loadTemplateFragment('html', 'tagsonrecord.phtml', $fields);
218
            } catch (RecordNotFoundException $e) {
219
                $msg = 'Unable to load the ActiveRecord of id ['.$params['ActiveRecordID'].'], error was ['.$e->getMessage().']';
220
                self::$logger->error($msg);
221
                throw new FileNotFoundException($msg);
222
            }
223
        } else {
224
            return parent::doGET($request);
225
        }
226
227
        $body .= View::displayPageFoot($this);
228
229
        self::$logger->debug('<<doGET');
230
231
        return new Response(200, $body, array('Content-Type' => 'text/html'));
232
    }
233
234
    /**
235
     * Handle POST requests.
236
     *
237
     * @param \Alpha\Util\Http\Request $request
238
     *
239
     * @return \Alpha\Util\Http\Response
240
     *
241
     * @throws \Alpha\Exception\SecurityException
242
     * @throws \Alpha\Exception\IllegalArguementException
243
     *
244
     * @since 1.0
245
     */
246
    public function doPOST($request)
247
    {
248
        self::$logger->debug('>>doPOST($request=['.var_export($request, true).'])');
249
250
        $params = $request->getParams();
251
252
        try {
253
            // check the hidden security fields before accepting the form POST data
254
            if (!$this->checkSecurityFields()) {
255
                throw new SecurityException('This page cannot accept post data from remote servers!');
256
            }
257
258
            if (isset($params['clearTaggedClass']) && $params['clearTaggedClass'] != '') {
259
                try {
260
                    self::$logger->info('About to start rebuilding the tags for the class ['.$params['clearTaggedClass'].']');
261
                    $startTime = microtime(true);
262
                    $record = new $params['clearTaggedClass']();
263
                    $records = $record->loadAll();
264
                    self::$logger->info('Loaded all of the active records (elapsed time ['.round(microtime(true)-$startTime, 5).'] seconds)');
265
                    ActiveRecord::begin();
266
                    $tag = new Tag();
267
                    $tag->deleteAllByAttribute('taggedClass', $params['clearTaggedClass']);
268
                    self::$logger->info('Deleted all of the old tags (elapsed time ['.round(microtime(true)-$startTime, 5).'] seconds)');
269
                    $this->regenerateTagsOnRecords($records);
270
                    self::$logger->info('Saved all of the new tags (elapsed time ['.round(microtime(true)-$startTime, 5).'] seconds)');
271
                    self::$logger->action('Tags recreated on the ['.$params['clearTaggedClass'].'] class');
272
                    ActiveRecord::commit();
273
                    $this->setStatusMessage(View::displayUpdateMessage('Tags recreated on the '.$record->getFriendlyClassName().' class.'));
274
                    self::$logger->info('Tags recreated on the ['.$params['clearTaggedClass'].'] class (time taken ['.round(microtime(true)-$startTime, 5).'] seconds).');
275
                } catch (AlphaException $e) {
276
                    self::$logger->error($e->getMessage());
277
                    ActiveRecord::rollback();
278
                }
279
                ActiveRecord::disconnect();
280
281
                return $this->doGET($request);
282
            } elseif (isset($params['ActiveRecordType']) && isset($params['ActiveRecordID'])) {
283
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
284
                $ActiveRecordID = $params['ActiveRecordID'];
285
286
                if (class_exists($ActiveRecordType)) {
287
                    $record = new $ActiveRecordType();
288
                } else {
289
                    throw new IllegalArguementException('No ActiveRecord available to display tags for!');
290
                }
291
292
                if (isset($params['saveBut'])) {
293
                    try {
294
                        $record->load($ActiveRecordID);
295
296
                        $tags = $record->getPropObject('tags')->getRelated();
297
298
                        ActiveRecord::begin();
299
300
                        foreach ($tags as $tag) {
301
                            $tag->set('content', Tag::cleanTagContent($params['content_'.$tag->getID()]));
302
                            $tag->save();
303
                            self::$logger->action('Saved tag '.$tag->get('content').' on '.$ActiveRecordType.' instance with ID '.$ActiveRecordID);
304
                        }
305
306
                        // handle new tag if posted
307
                        if (isset($params['NewTagValue']) && trim($params['NewTagValue']) != '') {
308
                            $newTag = new Tag();
309
                            $newTag->set('content', Tag::cleanTagContent($params['NewTagValue']));
310
                            $newTag->set('taggedID', $ActiveRecordID);
311
                            $newTag->set('taggedClass', $ActiveRecordType);
312
                            $newTag->save();
313
                            self::$logger->action('Created a new tag '.$newTag->get('content').' on '.$ActiveRecordType.' instance with ID '.$ActiveRecordID);
314
                        }
315
316
                        ActiveRecord::commit();
317
318
                        $this->setStatusMessage(View::displayUpdateMessage('Tags on '.get_class($record).' '.$record->getID().' saved successfully.'));
319
320
                        return $this->doGET($request);
321
                    } catch (ValidationException $e) {
322
                        /*
323
                         * The unique key has most-likely been violated because this Record is already tagged with this
324
                         * value.
325
                         */
326
                        ActiveRecord::rollback();
327
328
                        $this->setStatusMessage(View::displayErrorMessage('Tags on '.get_class($record).' '.$record->getID().' not saved due to duplicate tag values, please try again.'));
329
330
                        return $this->doGET($request);
331
                    } catch (FailedSaveException $e) {
332
                        self::$logger->error('Unable to save the tags of id ['.$params['ActiveRecordID'].'], error was ['.$e->getMessage().']');
333
                        ActiveRecord::rollback();
334
335
                        $this->setStatusMessage(View::displayErrorMessage('Tags on '.get_class($record).' '.$record->getID().' not saved, please check the application logs.'));
336
337
                        return $this->doGET($request);
338
                    }
339
                }
340
            } else {
341
                return parent::doPOST($request);
342
            }
343
        } catch (SecurityException $e) {
344
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
345
346
            self::$logger->warn($e->getMessage());
347
        } catch (IllegalArguementException $e) {
348
            self::$logger->error($e->getMessage());
349
        } catch (RecordNotFoundException $e) {
350
            self::$logger->warn($e->getMessage());
351
352
            $this->setStatusMessage(View::displayErrorMessage('Failed to load the requested item from the database!'));
353
        }
354
355
        self::$logger->debug('<<doPOST');
356
    }
357
358
    /**
359
     * Handle DELETE requests.
360
     *
361
     * @param \Alpha\Util\Http\Request $request
362
     *
363
     * @return \Alpha\Util\Http\Response
364
     *
365
     * @throws \Alpha\Exception\SecurityException
366
     * @throws \Alpha\Exception\IllegalArguementException
367
     *
368
     * @since 2.0
369
     */
370
    public function doDELETE($request)
371
    {
372
        self::$logger->debug('>>doDELETE($request=['.var_export($request, true).'])');
373
374
        $config = ConfigProvider::getInstance();
375
376
        $this->setName($config->get('app.url').$this->request->getURI());
377
        $this->setUnitOfWork(array($config->get('app.url').$this->request->getURI(), $config->get('app.url').$this->request->getURI()));
378
379
        $request->addParams(array('ActiveRecordType' => 'Alpha\Model\Tag'));
380
381
        self::$logger->debug('<<doDELETE');
382
383
        return parent::doDELETE($request);
384
    }
385
386
    /**
387
     * Regenerates the tags on the supplied list of active records.
388
     *
389
     * @param array $records
390
     *
391
     * @since 1.0
392
     */
393
    private function regenerateTagsOnRecords($records)
394
    {
395
        foreach ($records as $record) {
396
            foreach ($record->get('taggedAttributes') as $tagged) {
397
                $tags = Tag::tokenize($record->get($tagged), get_class($record), $record->getID());
398
                foreach ($tags as $tag) {
399
                    try {
400
                        $tag->save();
401
                    } catch (ValidationException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
402
                        /*
403
                         * The unique key has most-likely been violated because this record is already tagged with this
404
                         * value, so we can ignore in this case.
405
                         */
406
                    }
407
                }
408
            }
409
        }
410
    }
411
}
412