Completed
Pull Request — master (#2)
by Opeyemi
12:49
created

Model::save()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 20
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 20
rs 8.8571
cc 5
eloc 11
nc 5
nop 0
1
<?php
2
3
namespace Opeyemiabiodun\PotatoORM\Models;
4
5
use Exception;
6
use Opeyemiabiodun\PotatoORM\Connections\Connection;
7
use Opeyemiabiodun\PotatoORM\Connections\PgSqlConnection;
8
9
trait Model
10
{
11
    /**
12
     * The model's attributes.
13
     *
14
     * @var array
15
     */
16
    protected $_attributes = [];
17
18
    /**
19
     * The model's database connection.
20
     *
21
     * @var Opeyemiabiodun\PotatoORM\Connections\Connection
22
     */
23
    protected $_connection;
24
25
    /**
26
     * The primary key of the model's database table.
27
     *
28
     * @var string
29
     */
30
    protected $_primaryKey;
31
32
    /**
33
     * The model's database table.
34
     *
35
     * @var string
36
     */
37
    protected $_table;
38
39
    /**
40
     * The model's constructor method.
41
     *
42
     * @param Connection|null $connection An Opeyemiabiodun\PotatoORM\Connections\Connection instance or null
43
     * @param string          $table      The name of the model's table in the database
44
     */
45
    public function __construct(Connection $connection = null, $table = null)
46
    {
47
        if (is_null($connection)) {
48
            $this->setConnection(new PgSqlConnection());
49
        } else {
50
            $this->setConnection($connection);
51
        }
52
53
        if (is_null($table)) {
54
            $this->setTable(get_class($this).'-table');
55
        } else {
56
            $this->setTable($table);
57
        }
58
    }
59
60
    /**
61
     * The getter method for the model's properties.
62
     *
63
     * @param string $property The particular property
64
     *
65
     * @return int|float|string|bool The value of the property
66
     */
67
    public function __get($property)
68
    {
69
        if (array_key_exists($property, $_attributes)) {
70
            return $_attributes[$property];
0 ignored issues
show
Bug introduced by
The variable $_attributes does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
71
        } else {
72
            throw new Exception('Error Processing Request', 1);
73
        }
74
    }
75
76
    /**
77
     * The setter method for the model's properties.
78
     *
79
     * @param string                $property The particular property
80
     * @param int|float|string|bool $value    The value of the property
81
     */
82
    public function __set($property, $value)
83
    {
84
        if (!is_scalar($value)) {
85
            throw new Exception('Error Processing Request', 1);
86
        }
87
88
        if (array_key_exists($property, $_attributes)) {
0 ignored issues
show
Bug introduced by
The variable $_attributes seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
89
            $_attributes[$property] = $value;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$_attributes was never initialized. Although not strictly required by PHP, it is generally a good practice to add $_attributes = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
90
        } else {
91
            throw new Exception('Error Processing Request', 1);
92
        }
93
    }
94
95
    /**
96
     * Deletes a specified instance of the model in the database.
97
     *
98
     * @param int $number Specifies which model instance to delete; the 1st, 2nd, 3rd, .....
99
     *
100
     * @return bool Returns boolean true if the instance was successfully deleted or else it returns false.
101
     */
102 View Code Duplication
    public static function destroy($number)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
103
    {
104
        if ($number <= 0) {
105
            throw new Exception('Error Processing Request', 1);
106
        }
107
108
        return $this->_connection->deleteRecord($this->_table, $number - 1);
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
109
    }
110
111
    /**
112
     * Finds a specified instance of the model in the database.
113
     *
114
     * @param int $number Specifies which model instance to find; the 1st, 2nd, 3rd, .....
115
     *
116
     * @return array Returns the particular instance of the model.
117
     */
118 View Code Duplication
    public static function find($number)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
119
    {
120
        if ($number <= 0) {
121
            throw new Exception('Error Processing Request', 1);
122
        }
123
124
        return $this->_connection->findRecord($this->_table, $number - 1);
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
125
    }
126
127
    /**
128
     * Returns all instances of the model in the database.
129
     *
130
     * @return array All instances of the model in the database.
131
     */
132
    public static function getAll()
133
    {
134
        return $this->_connection->getAllRecords($this->_table);
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
135
    }
136
137
    /**
138
     * Checks the attributes of the model to ensure they are not all null.
139
     *
140
     * @return bool true if at least one of the models's attributes is not null else false.
141
     */
142
    private function hasAttributes()
143
    {
144
        $hasAttributes = false;
145
146
        foreach ($this->_attributes as $key => $value) {
147
            if (!is_null($value)) {
148
                $hasAttributes = true;
149
            }
150
        }
151
152
        return $hasAttributes;
153
    }
154
155
    /**
156
     * Saves or updates an instance of the model in the database.
157
     *
158
     * @return bool Returns true if the operation was successfully else returns false.
159
     */
160
    public function save()
161
    {
162
        if (is_null($this->_connection)) {
163
            throw new Exception('Error Processing Request', 1);
164
        }
165
166
        if (is_null($this->_table)) {
167
            throw new Exception('Error Processing Request', 1);
168
        }
169
170
        if (!$this->hasAttributes()) {
171
            throw new Exception('Error Processing Request', 1);
172
        }
173
174
        if (empty($this->_connection->findRecord($this->_table, $this->_attributes[getPrimaryKey($this->_table)]))) {
175
            return $this->_connection->createRecord($this->_table, $this->_attributes);
176
        } else {
177
            return $this->_connection->updateRecord($this->_table, $this->_attributes);
178
        }
179
    }
180
181
    /**
182
     * Sets the model's connection.
183
     *
184
     * @param Connection $connection An instance of Opeyemiabiodun\PotatoORM\Connections\Connection.
185
     */
186
    protected static function setConnection(Connection $connection)
187
    {
188
        $this->_connection = $connection;
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Documentation Bug introduced by
It seems like $connection of type object<Opeyemiabiodun\Po...Connections\Connection> is incompatible with the declared type object<Opeyemiabiodun\Po...Connections\Connection> of property $_connection.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
189
    }
190
191
    /**
192
     * Sets the model's table.
193
     *
194
     * @param string $table An existing table in the database.
195
     */
196
    protected static function setTable($table)
197
    {
198
        if (gettype($table) !== 'string') {
199
            throw new Exception('Error Processing Request', 1);
200
        }
201
202
        $this->_table = $table;
0 ignored issues
show
Bug introduced by
The variable $this does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
203
204
        $columns = $this->_connection->getColumns($table);
205
        for ($i = 0; $i < count($columns); $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...
206
            array_push($this->_attributes, $columns[i][key($columns[i])]);
207
        }
208
209
        $this->_primaryKey = $this->_connection->getPrimaryKey($table);
210
    }
211
}
212