Completed
Push — master ( e6990f...463166 )
by Michael
05:51 queued 03:04
created

TagTagHandler::getByItem()   D

Complexity

Conditions 9
Paths 42

Size

Total Lines 25
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 9
eloc 17
c 4
b 0
f 0
nc 42
nop 3
dl 0
loc 25
rs 4.909
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 28 and the first side effect is on line 23.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
/**
13
 * XOOPS tag management module
14
 *
15
 * @package         tag
16
 * @subpackage      class
17
 * @copyright       {@link http://sourceforge.net/projects/xoops/ The XOOPS Project}
18
 * @license         {@link http://www.fsf.org/copyleft/gpl.html GNU public license}
19
 * @author          Taiwen Jiang <[email protected]>
20
 * @since           1.00
21
 */
22
23
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
24
25
/**
26
 * Class TagTag
27
 */
28
class TagTag extends XoopsObject
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
29
{
30
    /**
31
     * TagTag constructor.
32
     */
33
    public function __construct()
34
    {
35
        $this->initVar('tag_id', XOBJ_DTYPE_INT, null, false);
36
        $this->initVar('tag_term', XOBJ_DTYPE_TXTBOX, '', true);
37
        $this->initVar('tag_status', XOBJ_DTYPE_INT, 0);
38
        $this->initVar('tag_count', XOBJ_DTYPE_INT, 0);
39
    }
40
}
41
42
/**
43
 * Class TagTagHandler
44
 */
45
class TagTagHandler extends XoopsPersistableObjectHandler
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
46
{
47
    public $table_link;
48
    public $table_stats;
49
50
    /**
51
     * Constructor
52
     *
53
     * @param XoopsDatabase $db reference to the {@link XoopsDatabase} object
54
     **/
55
    public function __construct(XoopsDatabase $db)
56
    {
57
        parent::__construct($db, 'tag_tag', 'TagTag', 'tag_id', 'tag_term');
58
        $this->table_link  = $this->db->prefix('tag_link');
59
        $this->table_stats = $this->db->prefix('tag_stats');
60
    }
61
62
    /**
63
     * Get tags linked to an item
64
     *
65
     * @access public
66
     * @param  int $itemid item ID
67
     * @param  int $modid  module ID, optional
68
     * @param  int $catid  id of corresponding category, optional
69
     * @return array associative array of tags (id, term)
70
     */
71
    public function getByItem($itemid, $modid = 0, $catid = 0)
0 ignored issues
show
Coding Style introduced by
getByItem uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
72
    {
73
        $ret = array();
74
75
        $itemid = (int)$itemid;
76
        $modid  = (empty($modid) && is_object($GLOBALS['xoopsModule']) && 'tag' !== $GLOBALS['xoopsModule']->getVar('dirname')) ? $GLOBALS['xoopsModule']->getVar('mid') : (int)$modid;
77
        if (empty($itemid) || empty($modid)) {
78
            return $ret;
79
        }
80
81
        $sql = 'SELECT o.tag_id, o.tag_term'
82
               . " FROM {$this->table_link} AS l "
83
               . " LEFT JOIN {$this->table} AS o ON o.{$this->keyName} = l.{$this->keyName} "
84
               . " WHERE  l.tag_itemid = {$itemid} AND l.tag_modid = {$modid}"
85
               . (empty($catid) ? '' : (' AND l.tag_catid=' . (int)$catid))
86
               . ' ORDER BY o.tag_count DESC';
87
        if (false == ($result = $this->db->query($sql))) {
88
            return $ret;
89
        }
90
        while ($myrow = $this->db->fetchArray($result)) {
91
            $ret[$myrow[$this->keyName]] = $myrow['tag_term'];
92
        }
93
94
        return $ret;
95
    }
96
97
    /**
98
     * Update tags linked to an item
99
     *
100
     * @access   public
101
     * @param             $tags
102
     * @param  int        $itemid item ID
103
     * @param  int|string $modid  module ID or module dirname, optional
104
     * @param  int        $catid  id of corresponding category, optional
105
     * @return bool
106
     * @internal param array|string $array of $tags   or a single tag
107
     */
108
    public function updateByItem($tags, $itemid, $modid = '', $catid = 0)
0 ignored issues
show
Coding Style introduced by
updateByItem uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
109
    {
110
        $catid  = (int)$catid;
111
        $itemid = (int)$itemid;
112
113
        if (!empty($modid) && !is_numeric($modid)) {
114
            if (($GLOBALS['xoopsModule'] instanceof XoopsModule) && ($modid == $GLOBALS['xoopsModule']->getVar('dirname'))) {
0 ignored issues
show
Bug introduced by
The class XoopsModule does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
115
                $modid = $GLOBALS['xoopsModule']->getVar('mid');
116
            } else {
117
                $moduleHandler = xoops_getHandler('module');
118
                $modid         = ($module_obj = $moduleHandler->getByDirname($modid)) ? $module_obj->getVar('mid') : 0;
119
            }
120
        } elseif ($GLOBALS['xoopsModule'] instanceof XoopsModule) {
0 ignored issues
show
Bug introduced by
The class XoopsModule does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
121
            $modid = $GLOBALS['xoopsModule']->getVar('mid');
122
        }
123
124
        if (empty($itemid) || empty($modid)) {
125
            return false;
126
        }
127
128
        if (empty($tags)) {
129
            $tags = array();
130
        } elseif (!is_array($tags)) {
131
            include_once $GLOBALS['xoops']->path('/modules/tag/include/functions.php');
132
            $tags = tag_parse_tag(addslashes(stripslashes($tags)));
133
        }
134
135
        $tags_existing = $this->getByItem($itemid, $modid, $catid);
136
        $tags_delete   = array_diff(array_values($tags_existing), $tags);
137
        $tags_add      = array_diff($tags, array_values($tags_existing));
138
        $tags_update   = array();
139
140
        if (!empty($tags_delete)) {
141
            $tags_delete = array_map(array($this->db, 'quoteString'), $tags_delete);
142
            if ($tags_id =& $this->getIds(new Criteria('tag_term', '(' . implode(', ', $tags_delete) . ')', 'IN'))) {
143
                $sql = "DELETE FROM {$this->table_link}"
144
                       . ' WHERE '
145
                       . "     {$this->keyName} IN ("
146
                       . implode(', ', $tags_id)
147
                       . ')'
148
                       . "     AND tag_modid = {$modid} AND tag_catid = {$catid} AND tag_itemid = {$itemid}";
149
                if (false == ($result = $this->db->queryF($sql))) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
150
                    //@todo: decide if we should do something here on failure
151
                }
152
                $sql = 'DELETE FROM ' . $this->table . ' WHERE ' . '    tag_count < 2 AND ' . "     {$this->keyName} IN (" . implode(', ', $tags_id) . ')';
153
                if (false == ($result = $this->db->queryF($sql))) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
154
                    //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
155
                }
156
157
                $sql = 'UPDATE ' . $this->table . ' SET tag_count = tag_count - 1' . ' WHERE ' . "     {$this->keyName} IN (" . implode(', ', $tags_id) . ')';
158
                if (false == ($result = $this->db->queryF($sql))) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
159
                    //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
160
                }
161
                $tags_update = $tags_id;
162
            }
163
        }
164
165
        if (!empty($tags_add)) {
166
            $tag_link  = array();
167
            $tag_count = array();
168
            foreach ($tags_add as $tag) {
169
                if ($tags_id =& $this->getIds(new Criteria('tag_term', $tag))) {
170
                    $tag_id      = $tags_id[0];
171
                    $tag_count[] = $tag_id;
172
                } else {
173
                    $tag_obj = $this->create();
174
                    $tag_obj->setVar('tag_term', $tag);
175
                    $tag_obj->setVar('tag_count', 1);
176
                    $this->insert($tag_obj);
177
                    $tag_id = $tag_obj->getVar('tag_id');
178
                    unset($tag_obj);
179
                }
180
                $tag_link[]    = "({$tag_id}, {$itemid}, {$catid}, {$modid}, " . time() . ')';
181
                $tags_update[] = $tag_id;
182
            }
183
            $sql = "INSERT INTO {$this->table_link}" . ' (tag_id, tag_itemid, tag_catid, tag_modid, tag_time) ' . ' VALUES ' . implode(', ', $tag_link);
184
            if (($result = $this->db->queryF($sql)) == false) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
185
                //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
186
            }
187
            if (!empty($tag_count)) {
188
                $sql = 'UPDATE ' . $this->table . ' SET tag_count = tag_count+1' . ' WHERE ' . "     {$this->keyName} IN (" . implode(', ', $tag_count) . ')';
189
                if (false == ($result = $this->db->queryF($sql))) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
190
                    //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
191
                }
192
            }
193
        }
194
        foreach ($tags_update as $tag_id) {
0 ignored issues
show
Bug introduced by
The expression $tags_update of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
195
            $this->update_stats($tag_id, $modid, $catid);
196
        }
197
198
        return true;
199
    }
200
201
    /**
202
     *
203
     * Update count stats sor tag
204
     *
205
     * @access public
206
     * @param  int $tag_id
207
     * @param  int $modid
208
     * @param  int $catid
209
     * @return bool
210
     */
211
    public function update_stats($tag_id, $modid = 0, $catid = 0)
212
    {
213
        $tag_id = (int)$tag_id;
214
        if (empty($tag_id)) {
215
            return true;
216
        }
217
218
        $modid = (int)$modid;
219
        $catid = empty($modid) ? -1 : (int)$catid;
220
        $count = 0;
221
        $sql   =
222
            'SELECT COUNT(*) ' . " FROM {$this->table_link}" . " WHERE tag_id = {$tag_id}" . (empty($modid) ? '' : " AND tag_modid = {$modid}") . (($catid < 0) ? '' : " AND tag_catid = {$catid}");
223
224
        if ($result = $this->db->query($sql)) {
225
            list($count) = $this->db->fetchRow($result);
226
        }
227
        if (empty($modid)) {
228
            $tag_obj = $this->get($tag_id);
229
            if (empty($count)) {
230
                $this->delete($tag_obj);
231
            } else {
232
                $tag_obj->setVar('tag_count', $count);
233
                $this->insert($tag_obj, true);
234
            }
235
        } else {
236
            if (empty($count)) {
237
                $sql = "DELETE FROM {$this->table_stats}" . ' WHERE ' . " {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}";
238
239
                if (false == $result = $this->db->queryF($sql)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
240
                    //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
241
                }
242
            } else {
243
                $ts_id = null;
244
                $sql   = 'SELECT ts_id, tag_count ' . " FROM {$this->table_stats}" . " WHERE {$this->keyName} = {$tag_id}" . " AND tag_modid = {$modid}" . " AND tag_catid = {$catid}";
245
                if ($result = $this->db->query($sql)) {
246
                    list($ts_id, $tag_count) = $this->db->fetchRow($result);
247
                }
248
                $sql = '';
249
                if ($ts_id && $tag_count != $count) {
0 ignored issues
show
Bug introduced by
The variable $tag_count does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
250
                    $sql = "UPDATE {$this->table_stats}" . " SET tag_count = {$count}" . ' WHERE ' . "     ts_id = {$ts_id}";
251
                } elseif (!$ts_id) {
252
                    $sql = "INSERT INTO {$this->table_stats}" . ' (tag_id, tag_modid, tag_catid, tag_count)' . " VALUES ({$tag_id}, {$modid}, {$catid}, {$count})";
253
                }
254
255
                if (!empty($sql) && ($result = $this->db->queryF($sql)) == false) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
256
                    //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
257
                }
258
            }
259
        }
260
261
        return true;
262
    }
263
264
    /**
265
     * Get tags with item count
266
     *
267
     * @access         public
268
     * @param int             $limit
269
     * @param int             $start
270
     * @param CriteriaElement $criteria  {@link Criteria}
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be null|CriteriaElement?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
271
     * @param null            $fields
272
     * @param boolean         $fromStats fetch from tag-stats table
273
     * @return array associative array of tags (id, term, count)
0 ignored issues
show
Documentation introduced by
Should the return type not be null|array?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
274
     */
275
    public function &getByLimit($limit = 0, $start = 0, CriteriaElement $criteria = null, $fields = null, $fromStats = true)//&getByLimit($criteria = null, $fromStats = true)
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
276
    {
277
        $ret = array();
278
        if ($fromStats) {
279
            $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, SUM(l.tag_count) AS count, l.tag_modid"
280
                   . " FROM {$this->table} AS o LEFT JOIN {$this->table_stats} AS l ON l.{$this->keyName} = o.{$this->keyName}";
281
        } else {
282
            $sql = "SELECT DISTINCT(o.{$this->keyName}), o.tag_term, o.tag_status, COUNT(l.tl_id) AS count, l.tag_modid"
283
                   . " FROM {$this->table} AS o LEFT JOIN {$this->table_link} AS l ON l.{$this->keyName} = o.{$this->keyName}";
284
        }
285
286
        $limit = null;
287
        $start = null;
288
        $sort  = '';
289
        $order = '';
290 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'CriteriaElement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
291
            $sql .= ' ' . $criteria->renderWhere();
292
            $sort  = $criteria->getSort();
293
            $order = $criteria->getOrder();
294
            $limit = $criteria->getLimit();
295
            $start = $criteria->getStart();
296
        }
297
        $sql .= " GROUP BY o.{$this->keyName}";
298
299
        $order = mb_strtoupper($order);
300
        $sort  = mb_strtolower($sort);
301
        switch ($sort) {
302
            case 'a':
303
            case 'alphabet':
304
                $order = ('DESC' !== $order) ? 'ASC' : 'DESC';
305
                $sql .= " ORDER BY o.tag_term {$order}";
306
                break;
307
            case 'id':
308
            case 'time':
309
                $order = ('ASC' !== $order) ? 'DESC' : 'ASC';
310
                $sql .= " ORDER BY o.{$this->keyName} {$order}";
311
                break;
312
            case 'c':
313
            case 'count':
314
            default:
315
                $order = ('ASC' !== $order) ? 'DESC' : 'ASC';
316
                $sql .= " ORDER BY count {$order}";
317
                break;
318
        }
319
320
        if (false == ($result = $this->db->query($sql, $limit, $start))) {
321
            //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
322
            $ret = null;
323
        } else {
324
            while ($myrow = $this->db->fetchArray($result)) {
325
                $ret[$myrow[$this->keyName]] = array(
326
                    'id'     => $myrow[$this->keyName],
327
                    'term'   => htmlspecialchars($myrow['tag_term']),
328
                    'status' => $myrow['tag_status'],
329
                    'modid'  => $myrow['tag_modid'],
330
                    'count'  => (int)$myrow['count']
331
                );
332
            }
333
        }
334
335
        return $ret;
336
    }
337
338
    /**
339
     * Get count of tags
340
     *
341
     * @access public
342
     * @param CriteriaElement $criteria {@link Criteria)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $criteria not be null|CriteriaElement?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
343
     *
344
     * @return integer count
345
     */
346
    public function getCount(CriteriaElement $criteria = null)
347
    {
348
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
349
        $catid    = (int)($catid);
350
        $modid    = (int)($modid);
351
        */
352
        $sql = "SELECT COUNT(DISTINCT o.{$this->keyName})" . "    FROM {$this->table} AS o LEFT JOIN {$this->table_link} AS l ON l.{$this->keyName} = o.{$this->keyName}";
353
        if (isset($criteria) && is_subclass_of($criteria, 'CriteriaElement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
354
            $sql .= ' ' . $criteria->renderWhere();
355
        }
356
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
357
        $sql_where    = "    WHERE 1 = 1";
358
        if (!empty($modid)) {
359
            $sql_where    .= " AND l.tag_modid = {$modid}";
360
        }
361
        if (empty($catid) || $catid > 0) {
362
            $sql_where    .= " AND l.tag_catid = {$catid}";
363
        }
364
365
        $sql =     $sql_select . " " . $sql_from . " " . $sql_where;
366
        */
367 View Code Duplication
        if (($result = $this->db->query($sql)) == false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
368
            //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
369
            $ret = 0;
370
        } else {
371
            list($ret) = $this->db->fetchRow($result);
372
        }
373
374
        return $ret;
375
    }
376
377
    /**
378
     * Get items linked with a tag
379
     *
380
     * @param object criteria {@link Criteria}
381
     *
382
     * @return array associative array of items (id, modid, catid)
383
     */
384
    public function &getItems($criteria = null)
385
    {
386
        $ret = array();
387
        $sql = '    SELECT o.tl_id, o.tag_itemid, o.tag_modid, o.tag_catid, o.tag_time';
388
        $sql .= "    FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}";
389
390
        $limit = null;
391
        $start = null;
392
        $sort  = '';
393
        $order = '';
394 View Code Duplication
        if (isset($criteria) && is_subclass_of($criteria, 'CriteriaElement')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
395
            $sql .= ' ' . $criteria->renderWhere();
396
            $sort  = $criteria->getSort();
397
            $order = $criteria->getOrder();
398
            $limit = $criteria->getLimit();
399
            $start = $criteria->getStart();
400
        }
401
402
        $order = mb_strtoupper($order);
403
        $sort  = mb_strtolower($sort);
404
        switch ($sort) {
405
            case 'i':
406
            case 'item':
407
                $order = ('DESC' !== $order) ? 'ASC' : 'DESC';
408
                $sql .= "    ORDER BY o.tag_itemid {$order}, o.tl_id DESC";
409
                break;
410
            case 'm':
411
            case 'module':
412
                $order = ('DESC' !== $order) ? 'ASC' : 'DESC';
413
                $sql .= "    ORDER BY o.tag_modid {$order}, o.tl_id DESC";
414
                break;
415
            case 't':
416
            case 'time':
417
            default:
418
                $order = ('ASC' !== $order) ? 'DESC' : 'ASC';
419
                $sql .= "    ORDER BY o.tl_id {$order}";
420
                break;
421
        }
422
423
        if (false == ($result = $this->db->query($sql, $limit, $start))) {
424
            //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
425
            $ret = array();
426
        } else {
427
            while ($myrow = $this->db->fetchArray($result)) {
428
                $ret[$myrow['tl_id']] = array(
429
                    'itemid' => $myrow['tag_itemid'],
430
                    'modid'  => $myrow['tag_modid'],
431
                    'catid'  => $myrow['tag_catid'],
432
                    'time'   => $myrow['tag_time']
433
                );
434
            }
435
        }
436
437
        return $ret;
438
    }
439
440
    /**
441
     * Get count of items linked with a tag
442
     *
443
     * @access public
444
     * @param  int $tag_id
445
     * @param  int $modid id of corresponding module, optional: 0 for all; >1 for a specific module
446
     * @param  int $catid id of corresponding category, optional
447
     * @return integer count
448
     */
449
    public function getItemCount($tag_id, $modid = 0, $catid = 0)
450
    {
451
        if (!$tag_id = (int)$tag_id) {
452
            $ret = 0;
453
        } else {
454
            $catid = (int)$catid;
455
            $modid = (int)$modid;
456
457
            $sql_select = '    SELECT COUNT(DISTINCT o.tl_id)';
458
            $sql_from   = "    FROM {$this->table_link} AS o LEFT JOIN {$this->table} AS l ON l.{$this->keyName} = o.{$this->keyName}";
459
            $sql_where  = "    WHERE o.tag_id = {$tag_id}";
460
            if (!empty($modid)) {
461
                $sql_where .= " AND o.tag_modid = {$modid}";
462
            }
463
            if (empty($catid) || $catid > 0) {
464
                $sql_where .= " AND o.tag_catid = {$catid}";
465
            }
466
467
            $sql = $sql_select . ' ' . $sql_from . ' ' . $sql_where;
468 View Code Duplication
            if (($result = $this->db->query($sql)) == false) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
469
                //xoops_error($this->db->error());
0 ignored issues
show
Unused Code Comprehensibility introduced by
73% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
470
                $ret = 0;
471
            } else {
472
                list($ret) = $this->db->fetchRow($result);
473
            }
474
        }
475
476
        return $ret;
477
    }
478
479
    /**
480
     * delete an object as well as links relying on it
481
     *
482
     * @access public
483
     * @param  XoopsObject |TagTag $object $object {@link TagTag}
484
     * @param  bool                $force  flag to force the query execution despite security settings
485
     * @return bool
486
     */
487
    public function delete(XoopsObject $object, $force = true)
488
    {
489
        /* {@internal - this isn't needed if we type hint TagTag}
490
        if (!is_object($object) || !$object->getVar($this->keyName)) {
491
            return false;
492
        }
493
        */
494
        $queryFunc = empty($force) ? 'query' : 'queryF';
0 ignored issues
show
Unused Code introduced by
$queryFunc is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
495
496
        /*
497
         * Remove item-tag links
498
         */
499
        $sql = 'DELETE' . " FROM {$this->table_link}" . " WHERE  {$this->keyName} = " . $object->getVar($this->keyName);
0 ignored issues
show
Unused Code introduced by
$sql is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
500
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
501
                if (false ==  ($result = $this->db->{$queryFunc}($sql))) {
502
                   // xoops_error($this->db->error());
503
                }
504
        */
505
        /*
506
         * Remove stats-tag links
507
         */
508
        $sql = 'DELETE' . " FROM {$this->table_stats}" . " WHERE  {$this->keyName} = " . $object->getVar($this->keyName);
0 ignored issues
show
Unused Code introduced by
$sql is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
509
        /*
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
510
                if (false == ($result = $this->db->{$queryFunc}($sql))) {
511
                   // xoops_error($this->db->error());
512
                }
513
        */
514
        return parent::delete($object, $force);
515
    }
516
517
    /**
518
     * clean orphan links from database
519
     *
520
     * @access public
521
     * @param string $table_link
522
     * @param string $field_link
523
     * @param string $field_object
524
     * @return bool true on success
525
     */
526
    public function cleanOrphan($table_link = '', $field_link = '', $field_object = '')
0 ignored issues
show
Coding Style introduced by
cleanOrphan uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
527
    {
528
        include_once $GLOBALS['xoops']->path('/modules/tag/functions.recon.php');
529
        //mod_loadFunctions("recon");
530
        return tag_cleanOrphan();
531
    }
532
533
    /**
534
     * get item Ids {@see XoopsPersistableObjectHandler}
535
     * Overloads default method to provide type hint since
536
     * this is a public function called by plugins
537
     *
538
     * @access public
539
     * @param  CriteriaElement $ids
0 ignored issues
show
Documentation introduced by
Should the type for parameter $ids not be null|CriteriaElement?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
540
     * @return array|bool      object IDs or false on failure
541
     */
542
    public function &getIds(CriteriaElement $ids = null)
543
    {
544
        return parent::getIds($ids);
545
    }
546
}
547