Completed
Push — master ( c8a39f...4d6955 )
by Christopher
43:34 queued 28:41
created

Potato::getTableNameFromClass()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4286
cc 2
eloc 8
nc 2
nop 0
1
<?php
2
3
namespace Ganga\Potato;
4
5
use ReflectionClass;
6
7
/**
8
 * Class that defines Potato ORM
9
 * Will be extended by Model Classes
10
 */
11
class Potato
12
{
13
    protected $tableName;
14
    protected static $id = null;
15
    protected static $table;
16
17
    /**
18
     * Constructor
19
     * TableName is set when the class is extended
20
     */
21
    public function __construct()
22
    {
23
        /**
24
         * Tests if the Model has defined a table name
25
         * if not it assigns it to the name of the class
26
         */
27
        if (!$this->tableName)
28
        {
29
            $ref = new ReflectionClass($this);
30
            $tableName = strtolower($ref->getShortName()).'s';
31
        }
32
33
        // Test if table exists else throw an exception
34
        if (!self::tableExists($tableName)) {
35
            throw new PotatoException("Table $tableName does not exist.");
36
        } else {
37
            $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...
38
            self::$table = $tableName;
39
        }
40
    }
41
42
    /**
43
     * Checks if a given table exists in the database
44
     * @param  string $tableName name of the table to be checked
45
     * @return bool           true if table is found, false otherwise
46
     */
47
    public static function tableExists($tableName)
48
    {
49
        $query = "SELECT name FROM sqlite_master WHERE type='table' AND name='$tableName';";
50
        $exists = Connection::db()->querySingle($query, true);
51
52
        if (empty($exists)) {
53
            return false;
54
        } else {
55
            return true;
56
        }
57
    }
58
59
    /**
60
     * Get the name of the current table
61
     * @return String table name
62
     */
63
    public function getTableName()
64
    {
65
        return $this->tableName;
66
    }
67
68
    /**
69
     * Getting table names from a class
70
     * This is important when no instance of the class is defined
71
     * Like User::getAll()
72
     * @return string table name
73
     */
74
    public static function getTableNameFromClass()
75
    {
76
        $instance = new static();
77
        $ref = new ReflectionClass($instance);
78
        $name = $ref->getShortName();
79
        $table = strtolower($name) . 's';
80
81
        if (!self::tableExists($table)) {
82
            throw new PotatoException("Table $table does not exist.");
83
        }
84
85
        return $table;
86
    }
87
88
    /**
89
     * Get all records from the record table
90
     * @return array associative array of the records received from the database
91
     */
92
    public static function getAll()
93
    {
94
        $table = self::getTableNameFromClass();
95
96
        $query = "SELECT * FROM $table";
97
        $results = Connection::db()->query($query);
98
        $res = [];
99
100
        while ($row = $results->fetchArray(SQLITE3_ASSOC)) {
101
            array_push($res, $row);
102
        }
103
104
        return $res;
105
    }
106
107
    /**
108
     * Get one record from the table based on the id provided
109
     * @param  integer $id id of the record to be retrieved
110
     * @return array     associative array of the record retrieved
111
     */
112
    public static function getOne($id)
113
    {
114
        $table = self::getTableNameFromClass();
115
116
        $query = "SELECT * FROM $table WHERE id = $id";
117
        $results = Connection::db()->query($query);
118
        $res = [];
119
120
        while ($row = $results->fetchArray(SQLITE3_ASSOC)) {
121
            array_push($res, $row);
122
        }
123
124
        if (!empty($res)) {
125
            return $res;
126
        } else {
127
            throw new PotatoException('There is no user with id '. $id);
128
        }
129
    }
130
131
    /**
132
     * Get table column names
133
     * @return array array containing the table column names
134
     */
135
    public function getColumnNames()
136
    {
137
        $query = Connection::db()->query("PRAGMA table_info($this->tableName);");
138
        $columns = [];
139
140
        while ($row = $query->fetchArray(SQLITE3_ASSOC)) {
141
            array_push($columns, $row['name']);
142
        }
143
144
        return $columns;
145
    }
146
147
    /**
148
     * Save either a new or existing record
149
     * @return integer 1 is successful, 0 if false
150
     */
151
    public function save()
152
    {
153
        $columnNames = $this->getColumnNames();
154
        $availableColumnNames = [];
155
        $availableColumnValues = [];
156
157
        foreach ($columnNames as $columnName)
158
        {
159
            if (isset($this->{$columnName})) {
160
                array_push($availableColumnNames, $columnName);
161
                array_push($availableColumnValues, $this->{$columnName});
162
            }
163
        }
164
165
        if (!self::$id) {
166
            // new record so we insert
167
            $query = "INSERT INTO $this->tableName (".implode(", ", $availableColumnNames).") VALUES('".implode("', '", $availableColumnValues)."');";
168
        } else {
169
            // existing record, se we update
170
            $query = "UPDATE $this->tableName SET ";
171
172
            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...
173
                $prop = $availableColumnNames[$i];
174
                $query .= " $prop = '". $this->{$prop}."'";
175
176
                if ($i != count($availableColumnNames) - 1) {
177
                    $query .= ",";
178
                }
179
            }
180
181
            $query .= " WHERE id = ".self::$id;
182
        }
183
184
        $result = Connection::db()->query($query);
185
186
        if (!$result) {
187
            return 0;
188
        } else {
189
            return 1;
190
        }
191
    }
192
193
    /**
194
     * Find a record by id and change static id param
195
     * @param  int $id id of the record to be found
196
     * @return ClassInstance     an instance of the TableClass so that properties can be assigned automatically
197
     */
198
    public static function find($id)
199
    {
200
        self::getOne($id);
201
        self::$id = $id;
202
        return new static();
203
    }
204
205
    /**
206
     * Delete a record by id from the table in context
207
     * @param  id $id the id of the record to be deleted
208
     * @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...
209
     */
210
    public static function destroy($id)
211
    {
212
        $table = self::getTableNameFromClass();
213
214
        self::getOne($id);
215
216
        $query = "DELETE FROM $table WHERE id = ".$id;
217
218
        $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...
219
    }
220
}
221