Completed
Pull Request — master (#16)
by Christopher
38:26 queued 23:20
created

Potato::save()   C

Complexity

Conditions 9
Paths 36

Size

Total Lines 53
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 7
Bugs 2 Features 3
Metric Value
c 7
b 2
f 3
dl 0
loc 53
rs 6.8963
cc 9
eloc 30
nc 36
nop 0

How to fix   Long Method   

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 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
            $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 1 FROM $tableName LIMIT 1";
50
51
        try {
52
            $result = Connection::db()->query($query);
53
        } 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...
54
            return false;
55
        }
56
57
        return $result !== false;
58
    }
59
60
    /**
61
     * Get the name of the current table
62
     * @return String table name
63
     */
64
    public function getTableName()
65
    {
66
        return $this->tableName;
67
    }
68
69
    /**
70
     * Getting table names from a class
71
     * This is important when no instance of the class is defined
72
     * Like User::getAll()
73
     * @return string table name
74
     */
75
    public static function getTableNameFromClass()
76
    {
77
        $instance = new static();
78
        $ref = new ReflectionClass($instance);
79
        $name = $ref->getShortName();
80
        $table = strtolower($name) . 's';
81
82
        if (!self::tableExists($table)) {
83
            throw new PotatoException("Table $table does not exist.");
84
        }
85
86
        return $table;
87
    }
88
89
    /**
90
     * Get all records from the record table
91
     * @param array $fields array of fields to be retrieved
92
     * @return array associative array of the records received from the database
93
     */
94
    public static function getAll($fields = null)
95
    {
96
        $table = self::getTableNameFromClass();
97
98 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...
99
            $query =  "SELECT ". implode(', ', $fields) ." FROM $table";
100
        } else {
101
            $query = "SELECT * FROM $table";
102
        }
103
104
105
        $res = [];
106
107
        $results = Connection::db()->query($query);
108
        $results->setFetchMode(PDO::FETCH_ASSOC);
109
110
        while ($row = $results->fetch()) {
111
            array_push($res, $row);
112
        }
113
114
        return $res;
115
    }
116
117
    /**
118
     * Get one record from the table based on the id provided
119
     * @param  integer $id id of the record to be retrieved
120
     * @param array $fields array of fields to be retrieved
121
     * @return array     associative array of the record retrieved
122
     */
123
    public static function getOne($id, $fields = null)
124
    {
125
        $table = self::getTableNameFromClass();
126
127 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...
128
            $query = "SELECT ". implode(', ', $fields) ." FROM $table WHERE id = $id";
129
        } else {
130
            $query = "SELECT * FROM $table WHERE id = $id";
131
        }
132
133
        $res = [];
134
135
        $results = Connection::db()->query($query);
136
        $results->setFetchMode(PDO::FETCH_ASSOC);
137
138
        while ($row = $results->fetch()) {
139
            array_push($res, $row);
140
        }
141
142
        if (!empty($res)) {
143
            return $res;
144
        } else {
145
            throw new PotatoException('There is no user with id '. $id);
146
        }
147
    }
148
149
    /**
150
     * Get table column names
151
     * @return array array containing the table column names
152
     */
153
    public function getColumnNames()
154
    {
155
        $query = "SELECT * from $this->tableName limit 1";
156
        $result = Connection::db()->query($query);
157
        $fields = array_keys($result->fetch(PDO::FETCH_ASSOC));
158
        return $fields;
159
    }
160
161
    /**
162
     * Save either a new or existing record
163
     * @return integer 1 is successful, 0 if false
164
     */
165
    public function save()
166
    {
167
        $columnNames = $this->getColumnNames();
168
        $availableColumnNames = [];
169
        $availableColumnValues = [];
170
171
        foreach ($columnNames as $columnName) {
172
            if (isset($this->{$columnName})) {
173
                array_push($availableColumnNames, $columnName);
174
                array_push($availableColumnValues, $this->{$columnName});
175
            }
176
        }
177
178
        if (!self::$id) {
179
            // new record so we insert
180
            $query = "INSERT INTO $this->tableName (".implode(", ", $availableColumnNames).") VALUES(";
181
182
            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...
183
                $query .= "?";
184
185
                if ($i != count($availableColumnNames) - 1) {
186
                    $query .= ",";
187
                }
188
            }
189
190
            $query .= ");";
191
192
            $insert = Connection::db()->prepare($query);
193
            $insert->execute($availableColumnValues);
194
        } else {
195
            // existing record, se we update
196
            $query = "UPDATE $this->tableName SET ";
197
198
            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...
199
                $prop = $availableColumnNames[$i];
200
                $query .= " $prop = '". $this->{$prop}."'";
201
202
                if ($i != count($availableColumnNames) - 1) {
203
                    $query .= ",";
204
                }
205
            }
206
207
            $query .= " WHERE id = ".self::$id;
208
        }
209
210
        $result = Connection::db()->query($query);
211
212
        if (!$result) {
213
            return 0;
214
        } else {
215
            return 1;
216
        }
217
    }
218
219
    /**
220
     * Find a record by id and change static id param
221
     * @param  int $id id of the record to be found
222
     * @return ClassInstance     an instance of the TableClass so that properties can be assigned automatically
223
     */
224
    public static function find($id)
225
    {
226
        self::getOne($id);
227
        self::$id = $id;
228
        return new static();
229
    }
230
231
    /**
232
     * Delete a record by id from the table in context
233
     * @param  id $id the id of the record to be deleted
234
     * @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...
235
     */
236
    public static function destroy($id)
237
    {
238
        $table = self::getTableNameFromClass();
239
240
        self::getOne($id);
241
242
        $query = "DELETE FROM $table WHERE id = ".$id;
243
244
        try {
245
            Connection::db()->query($query);
246
            return true;
247
        } 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...
248
            return false;
249
        }
250
    }
251
}
252