Completed
Push — master ( ac6db6...9e1fb5 )
by Christopher
45:43 queued 25:48
created

Potato::getOne()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 25
Code Lines 15

Duplication

Lines 5
Ratio 20 %

Importance

Changes 7
Bugs 2 Features 1
Metric Value
c 7
b 2
f 1
dl 5
loc 25
rs 8.439
cc 5
eloc 15
nc 8
nop 2
1
<?php
2
3
namespace Ganga\Potato;
4
5
use ReflectionClass;
6
use PDO;
7
8
/**
9
 * Class that defines Potato ORM
10
 * Will be extended by Model Classes
11
 */
12
class Potato
13
{
14
    protected $tableName;
15
    protected static $id = null;
16
    protected static $table;
17
18
    /**
19
     * Constructor
20
     * TableName is set when the class is extended
21
     */
22
    public function __construct()
23
    {
24
        /**
25
         * Tests if the Model has defined a table name
26
         * if not it assigns it to the name of the class
27
         */
28
        if (!$this->tableName)
29
        {
30
            $ref = new ReflectionClass($this);
31
            $tableName = strtolower($ref->getShortName()).'s';
32
        }
33
34
        // Test if table exists else throw an exception
35
        if (!self::tableExists($tableName)) {
36
            throw new PotatoException("Table $tableName does not exist.");
37
        } else {
38
            $this->tableName = $tableName;
0 ignored issues
show
Bug introduced by
The variable $tableName 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...
39
            self::$table = $tableName;
40
        }
41
    }
42
43
    /**
44
     * Checks if a given table exists in the database
45
     * @param  string $tableName name of the table to be checked
46
     * @return bool           true if table is found, false otherwise
47
     */
48
    public static function tableExists($tableName)
49
    {
50
        $query = "SELECT 1 FROM $tableName LIMIT 1";
51
52
       try {
53
            $result = Connection::db()->query($query);
54
       } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Ganga\Potato\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
55
            return FALSE;
56
       }
57
58
       return $result !== FALSE;
59
    }
60
61
    /**
62
     * Get the name of the current table
63
     * @return String table name
64
     */
65
    public function getTableName()
66
    {
67
        return $this->tableName;
68
    }
69
70
    /**
71
     * Getting table names from a class
72
     * This is important when no instance of the class is defined
73
     * Like User::getAll()
74
     * @return string table name
75
     */
76
    public static function getTableNameFromClass()
77
    {
78
        $instance = new static();
79
        $ref = new ReflectionClass($instance);
80
        $name = $ref->getShortName();
81
        $table = strtolower($name) . 's';
82
83
        if (!self::tableExists($table)) {
84
            throw new PotatoException("Table $table does not exist.");
85
        }
86
87
        return $table;
88
    }
89
90
    /**
91
     * Get all records from the record table
92
     * @param array $fields array of fields to be retrieved
93
     * @return array associative array of the records received from the database
94
     */
95
    public static function getAll($fields = null)
96
    {
97
        $table = self::getTableNameFromClass();
98
99 View Code Duplication
        if ($fields != null && is_array($fields)) {
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...
100
            $query =  "SELECT ". implode(', ', $fields) ." FROM $table";
101
        } else {
102
            $query = "SELECT * FROM $table";
103
        }
104
105
106
        $res = [];
107
108
        $results = Connection::db()->query($query);
109
        $results->setFetchMode(PDO::FETCH_ASSOC);
110
111
        while ($row = $results->fetch()) {
112
            array_push($res, $row);
113
        }
114
115
        return $res;
116
    }
117
118
    /**
119
     * Get one record from the table based on the id provided
120
     * @param  integer $id id of the record to be retrieved
121
     * @param array $fields array of fields to be retrieved
122
     * @return array     associative array of the record retrieved
123
     */
124
    public static function getOne($id, $fields = null)
125
    {
126
        $table = self::getTableNameFromClass();
127
128 View Code Duplication
        if ($fields != null && is_array($fields)) {
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...
129
            $query = "SELECT ". implode(', ', $fields) ." FROM $table WHERE id = $id";
130
        } else {
131
            $query = "SELECT * FROM $table WHERE id = $id";
132
        }
133
134
        $res = [];
135
136
        $results = Connection::db()->query($query);
137
        $results->setFetchMode(PDO::FETCH_ASSOC);
138
139
        while ($row = $results->fetch()) {
140
            array_push($res, $row);
141
        }
142
143
        if (!empty($res)) {
144
            return $res;
145
        } else {
146
            throw new PotatoException('There is no user with id '. $id);
147
        }
148
    }
149
150
    /**
151
     * Get table column names
152
     * @return array array containing the table column names
153
     */
154
    public function getColumnNames()
155
    {
156
        $query = "SELECT * from $this->tableName limit 1";
157
        $result = Connection::db()->query($query);
158
        $fields = array_keys($result->fetch(PDO::FETCH_ASSOC));
159
        return $fields;
160
    }
161
162
    /**
163
     * Save either a new or existing record
164
     * @return integer 1 is successful, 0 if false
165
     */
166
    public function save()
167
    {
168
        $columnNames = $this->getColumnNames();
169
        $availableColumnNames = [];
170
        $availableColumnValues = [];
171
172
        foreach ($columnNames as $columnName)
173
        {
174
            if (isset($this->{$columnName})) {
175
                array_push($availableColumnNames, $columnName);
176
                array_push($availableColumnValues, $this->{$columnName});
177
            }
178
        }
179
180
        if (!self::$id) {
181
            // new record so we insert
182
            $query = "INSERT INTO $this->tableName (".implode(", ", $availableColumnNames).") VALUES(";
183
184
            for ($i = 0; $i < count($availableColumnNames); $i++)
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
185
            {
186
                $query .= "?";
187
188
                if ($i != count($availableColumnNames) - 1) {
189
                    $query .= ",";
190
                }
191
            }
192
193
            $query .= ");";
194
195
            $insert = Connection::db()->prepare($query);
196
            $insert->execute($availableColumnValues);
197
        } else {
198
            // existing record, se we update
199
            $query = "UPDATE $this->tableName SET ";
200
201
            for ($i = 0; $i < count($availableColumnNames); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
202
                $prop = $availableColumnNames[$i];
203
                $query .= " $prop = '". $this->{$prop}."'";
204
205
                if ($i != count($availableColumnNames) - 1) {
206
                    $query .= ",";
207
                }
208
            }
209
210
            $query .= " WHERE id = ".self::$id;
211
        }
212
213
        $result = Connection::db()->query($query);
214
215
        if (!$result) {
216
            return 0;
217
        } else {
218
            return 1;
219
        }
220
    }
221
222
    /**
223
     * Find a record by id and change static id param
224
     * @param  int $id id of the record to be found
225
     * @return ClassInstance     an instance of the TableClass so that properties can be assigned automatically
226
     */
227
    public static function find($id)
228
    {
229
        self::getOne($id);
230
        self::$id = $id;
231
        return new static();
232
    }
233
234
    /**
235
     * Delete a record by id from the table in context
236
     * @param  id $id the id of the record to be deleted
237
     * @return [type]     [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
238
     */
239
    public static function destroy($id)
240
    {
241
        $table = self::getTableNameFromClass();
242
243
        self::getOne($id);
244
245
        $query = "DELETE FROM $table WHERE id = ".$id;
246
247
        $result = Connection::db()->query($query);
0 ignored issues
show
Unused Code introduced by
$result 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...
248
    }
249
}
250