Completed
Push — develop ( 819d57...da80fe )
by Christopher
13:27
created

Potato::getColumnNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 1
Metric Value
c 3
b 0
f 1
dl 0
loc 7
rs 9.4286
cc 1
eloc 5
nc 1
nop 0
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
     * @return array associative array of the records received from the database
93
     */
94
    public static function getAll()
95
    {
96
        $table = self::getTableNameFromClass();
97
98
        $query = "SELECT * FROM $table";
99
100
        $res = [];
101
102
        $results = Connection::db()->query($query);
103
        $results->setFetchMode(PDO::FETCH_ASSOC);
104
105
        while ($row = $results->fetch()) {
106
            array_push($res, $row);
107
        }
108
109
        return $res;
110
    }
111
112
    /**
113
     * Get one record from the table based on the id provided
114
     * @param  integer $id id of the record to be retrieved
115
     * @return array     associative array of the record retrieved
116
     */
117
    public static function getOne($id)
118
    {
119
        $table = self::getTableNameFromClass();
120
121
        $query = "SELECT * FROM $table WHERE id = $id";
122
123
        $res = [];
124
125
        $results = Connection::db()->query($query);
126
        $results->setFetchMode(PDO::FETCH_ASSOC);
127
128
        while ($row = $results->fetch()) {
129
            array_push($res, $row);
130
        }
131
132
        if (!empty($res)) {
133
            return $res;
134
        } else {
135
            throw new PotatoException('There is no user with id '. $id);
136
        }
137
    }
138
139
    /**
140
     * Get table column names
141
     * @return array array containing the table column names
142
     */
143
    public function getColumnNames()
144
    {
145
        $query = "SELECT * from $this->tableName limit 1";
146
        $result = Connection::db()->query($query);
147
        $fields = array_keys($result->fetch(PDO::FETCH_ASSOC));
148
        return $fields;
149
    }
150
151
    /**
152
     * Save either a new or existing record
153
     * @return integer 1 is successful, 0 if false
154
     */
155
    public function save()
156
    {
157
        $columnNames = $this->getColumnNames();
158
        $availableColumnNames = [];
159
        $availableColumnValues = [];
160
161
        foreach ($columnNames as $columnName)
162
        {
163
            if (isset($this->{$columnName})) {
164
                array_push($availableColumnNames, $columnName);
165
                array_push($availableColumnValues, $this->{$columnName});
166
            }
167
        }
168
169
        if (!self::$id) {
170
            // new record so we insert
171
            $query = "INSERT INTO $this->tableName (".implode(", ", $availableColumnNames).") VALUES(";
172
173
            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...
174
            {
175
                $query .= "?";
176
177
                if ($i != count($availableColumnNames) - 1) {
178
                    $query .= ",";
179
                }
180
            }
181
182
            $query .= ");";
183
184
            $insert = Connection::db()->prepare($query);
185
            $insert->execute($availableColumnValues);
186
        } else {
187
            // existing record, se we update
188
            $query = "UPDATE $this->tableName SET ";
189
190
            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...
191
                $prop = $availableColumnNames[$i];
192
                $query .= " $prop = '". $this->{$prop}."'";
193
194
                if ($i != count($availableColumnNames) - 1) {
195
                    $query .= ",";
196
                }
197
            }
198
199
            $query .= " WHERE id = ".self::$id;
200
        }
201
202
        $result = Connection::db()->query($query);
203
204
        if (!$result) {
205
            return 0;
206
        } else {
207
            return 1;
208
        }
209
    }
210
211
    /**
212
     * Find a record by id and change static id param
213
     * @param  int $id id of the record to be found
214
     * @return ClassInstance     an instance of the TableClass so that properties can be assigned automatically
215
     */
216
    public static function find($id)
217
    {
218
        self::getOne($id);
219
        self::$id = $id;
220
        return new static();
221
    }
222
223
    /**
224
     * Delete a record by id from the table in context
225
     * @param  id $id the id of the record to be deleted
226
     * @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...
227
     */
228
    public static function destroy($id)
229
    {
230
        $table = self::getTableNameFromClass();
231
232
        self::getOne($id);
233
234
        $query = "DELETE FROM $table WHERE id = ".$id;
235
236
        $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...
237
    }
238
}
239