Completed
Push — d64 ( ca4f4f...a95f31 )
by Welling
02:17
created

ClientLocal   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 460
Duplicated Lines 6.52 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 30
loc 460
ccs 0
cts 270
cp 0
rs 8.6206
c 0
b 0
f 0
wmc 50
lcom 1
cbo 11

35 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getTables() 0 4 1
A getTable() 0 4 1
A getColumns() 0 4 1
A getColumn() 0 4 1
A getEntries() 0 6 1
A getEntry() 0 7 1
A getUsers() 0 5 1
A getUser() 0 4 1
A getGroups() 0 4 1
A getGroup() 0 4 1
A getGroupPrivileges() 0 8 1
A getFiles() 0 4 1
A getFile() 0 4 1
A getSettings() 0 4 1
A getSettingsByCollection() 0 8 1
A getMessages() 0 7 1
A createEntry() 15 15 3
A updateEntry() 15 15 3
A deleteEntry() 0 13 2
A createUser() 0 4 1
A updateUser() 0 4 1
A deleteUser() 0 4 1
A createFile() 0 6 1
A updateFile() 0 4 1
A deleteFile() 0 4 1
A createPreferences() 0 11 2
A createBookmark() 0 20 1
A createColumn() 0 10 1
A createGroup() 0 4 1
B createMessage() 0 52 6
A sendMessage() 0 4 1
A createPrivileges() 0 16 1
B createTable() 0 31 4
A getTableGateway() 0 9 2

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ClientLocal often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ClientLocal, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * Directus – <http://getdirectus.com>
5
 *
6
 * @link      The canonical repository – <https://github.com/directus/directus>
7
 * @copyright Copyright 2006-2016 RANGER Studio, LLC – <http://rangerstudio.com>
8
 * @license   GNU General Public License (v3) – <http://www.gnu.org/copyleft/gpl.html>
9
 */
10
11
namespace Directus\SDK;
12
13
use Directus\Database\Connection;
14
use Directus\Database\TableGateway\BaseTableGateway;
15
use Directus\Database\TableGateway\DirectusActivityTableGateway;
16
use Directus\Database\TableGateway\DirectusMessagesTableGateway;
17
use Directus\Database\TableGateway\DirectusPrivilegesTableGateway;
18
use Directus\Database\TableGateway\DirectusUsersTableGateway;
19
use Directus\Database\TableGateway\RelationalTableGateway;
20
use Directus\Database\TableSchema;
21
use Directus\Util\ArrayUtils;
22
use Directus\Util\SchemaUtils;
23
24
/**
25
 * Client Local
26
 *
27
 * Client to Interact with the database directly using Directus Database Component
28
 *
29
 * @author Welling Guzmán <[email protected]>
30
 */
31
class ClientLocal extends AbstractClient
32
{
33
    /**
34
     * @var BaseTableGateway[]
35
     */
36
    protected $tableGateways = [];
37
38
    /**
39
     * @var Connection
40
     */
41
    protected $connection = null;
42
43
    /**
44
     * ClientLocal constructor.
45
     *
46
     * @param $connection
47
     */
48
    public function __construct($connection)
49
    {
50
        $this->connection = $connection;
51
    }
52
53
    /**
54
     * @inheritDoc
55
     */
56
    public function getTables(array $params = [])
57
    {
58
        return $this->createResponseFromData(TableSchema::getTablesSchema($params));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...TablesSchema($params)); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\Entry to the return on line 58 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getTables of type Directus\SDK\Response\EntryCollection.
Loading history...
59
    }
60
61
    /**
62
     * @inheritDoc
63
     */
64
    public function getTable($tableName)
65
    {
66
        return $this->createResponseFromData(TableSchema::getSchemaArray($tableName));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...hemaArray($tableName)); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 66 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getTable of type Directus\SDK\Response\Entry.
Loading history...
67
    }
68
69
    /**
70
     * @inheritDoc
71
     */
72
    public function getColumns($tableName, array $params = [])
73
    {
74
        return $this->createResponseFromData(TableSchema::getColumnSchemaArray($tableName, $params));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...($tableName, $params)); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\Entry to the return on line 74 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getColumns of type Directus\SDK\Response\EntryCollection.
Loading history...
75
    }
76
77
    /**
78
     * @inheritDoc
79
     */
80
    public function getColumn($tableName, $columnName)
81
    {
82
        return $this->createResponseFromData(TableSchema::getColumnSchema($tableName, $columnName)->toArray());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...olumnName)->toArray()); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 82 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getColumn of type Directus\SDK\Response\Entry.
Loading history...
83
    }
84
85
    /**
86
     * @inheritDoc
87
     */
88
    public function getEntries($tableName, array $params = [])
89
    {
90
        $tableGateway = $this->getTableGateway($tableName);
91
92
        return $this->createResponseFromData($tableGateway->getEntries($params));
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...->getEntries($params)); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\Entry to the return on line 92 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getEntries of type Directus\SDK\Response\EntryCollection.
Loading history...
93
    }
94
95
    /**
96
     * @inheritDoc
97
     */
98
    public function getEntry($tableName, $id, array $params = [])
99
    {
100
        // @TODO: Dynamic ID
101
        return $this->getEntries($tableName, array_merge($params, [
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getEntries..., array('id' => $id))); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getEntry of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
102
            'id' => $id
103
        ]));
104
    }
105
106
    /**
107
     * @inheritDoc
108
     */
109
    public function getUsers(array $params = [])
110
    {
111
        // @TODO: store the directus tables somewhere (SchemaManager?)
112
        return $this->getEntries('directus_users', $params);
113
    }
114
115
    /**
116
     * @inheritDoc
117
     */
118
    public function getUser($id, array $params = [])
119
    {
120
        return $this->getEntry('directus_users', $id, $params);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getEntry('..._users', $id, $params); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getUser of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
121
    }
122
123
    /**
124
     * @inheritDoc
125
     */
126
    public function getGroups(array $params = [])
127
    {
128
        return $this->getEntries('directus_groups', $params);
129
    }
130
131
    /**
132
     * @inheritDoc
133
     */
134
    public function getGroup($id, array $params = [])
135
    {
136
        return $this->getEntry('directus_groups', $id, $params);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getEntry('...groups', $id, $params); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getGroup of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
137
    }
138
139
    /**
140
     * @inheritDoc
141
     */
142
    public function getGroupPrivileges($groupID)
143
    {
144
        $this->getEntries('directus_privileges', [
145
            'filter' => [
146
                'group_id' => ['eq' => $groupID]
147
            ]
148
        ]);
149
    }
150
151
    /**
152
     * @inheritDoc
153
     */
154
    public function getFiles(array $params = [])
155
    {
156
        return $this->getEntries('directus_files', $params);
157
    }
158
159
    /**
160
     * @inheritDoc
161
     */
162
    public function getFile($id, array $params = [])
163
    {
164
        return $this->getEntry('directus_files', $id, $params);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getEntry('..._files', $id, $params); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getFile of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
165
    }
166
167
    /**
168
     * @inheritDoc
169
     */
170
    public function getSettings()
171
    {
172
        return $this->getEntries('directus_settings');
173
    }
174
175
    /**
176
     * @inheritDoc
177
     */
178
    public function getSettingsByCollection($collectionName)
179
    {
180
        return $this->getEntries('directus_settings', [
181
            'filter' => [
182
                'collection' => ['eq' => $collectionName]
183
            ]
184
        ]);
185
    }
186
187
    /**
188
     * @inheritDoc
189
     */
190
    public function getMessages($userId)
191
    {
192
        $messagesTableGateway = new DirectusMessagesTableGateway($this->connection, null);
0 ignored issues
show
Documentation introduced by
null is of type null, but the function expects a object<Directus\Permissions\Acl>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
193
        $result = $messagesTableGateway->fetchMessagesInboxWithHeaders($userId);
194
195
        return $this->createResponseFromData($result);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFromData($result); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\Entry to the return on line 195 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::getMessages of type Directus\SDK\Response\EntryCollection.
Loading history...
196
    }
197
198
    /**
199
     * @inheritDoc
200
     */
201 View Code Duplication
    public function createEntry($tableName, array $data)
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...
202
    {
203
        $tableGateway = $this->getTableGateway($tableName);
204
        $data = $this->processData($tableName, $data);
205
206
        foreach($data as $key => $value) {
207
            if ($value instanceof File) {
208
                $data[$key] = $this->processFile($value);
209
            }
210
        }
211
212
        $newRecord = $tableGateway->manageRecordUpdate($tableName, $data);
213
214
        return $this->getEntry($tableName, $newRecord[$tableGateway->primaryKeyFieldName]);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->getEntry($...>primaryKeyFieldName]); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createEntry of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
215
    }
216
217
    /**
218
     * @inheritDoc
219
     */
220 View Code Duplication
    public function updateEntry($tableName, $id, array $data)
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...
221
    {
222
        $tableGateway = $this->getTableGateway($tableName);
223
        $data = $this->processData($tableName, $data);
224
225
        foreach($data as $key => $value) {
226
            if ($value instanceof File) {
227
                $data[$key] = $this->processFile($value);
228
            }
229
        }
230
231
        $updatedRecord = $tableGateway->manageRecordUpdate($tableName, array_merge($data, ['id' => $id]));
232
233
        return $this->getEntry($tableName, $updatedRecord[$tableGateway->primaryKeyFieldName]);
234
    }
235
236
    /**
237
     * @inheritDoc
238
     */
239
    public function deleteEntry($tableName, $ids)
240
    {
241
        // @TODO: Accept EntryCollection and Entry
242
        $tableGateway = $this->getTableGateway($tableName);
243
244
        if (!is_array($ids)) {
245
            $ids = [$ids];
246
        }
247
248
        return $tableGateway->delete(function($delete) use ($ids) {
249
            return $delete->where->in('id', $ids);
250
        });
251
    }
252
253
    /**
254
     * @inheritDoc
255
     */
256
    public function createUser(array $data)
257
    {
258
        return $this->createEntry('directus_users', $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createEntr...irectus_users', $data); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createUser of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
259
    }
260
261
    /**
262
     * @inheritDoc
263
     */
264
    public function updateUser($id, array $data)
265
    {
266
        return $this->updateEntry('directus_users', $id, $data);
267
    }
268
269
    /**
270
     * @inheritDoc
271
     */
272
    public function deleteUser($ids)
273
    {
274
        return $this->deleteEntry('directus_users', $ids);
275
    }
276
277
    /**
278
     * @inheritDoc
279
     */
280
    public function createFile(File $file)
281
    {
282
        $data = $this->processFile($file);
283
284
        return $this->createEntry('directus_files', $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createEntr...irectus_files', $data); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createFile of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
285
    }
286
287
    /**
288
     * @inheritDoc
289
     */
290
    public function updateFile($id, array $data)
291
    {
292
        return $this->updateEntry('directus_files', $id, $data);
293
    }
294
295
    /**
296
     * @inheritDoc
297
     */
298
    public function deleteFile($ids)
299
    {
300
        return $this->deleteEntry('directus_files', $ids);
301
    }
302
303
    public function createPreferences($data)
304
    {
305
        if (!ArrayUtils::contains($data, ['title', 'table_name'])) {
306
            throw new \Exception('title and table_name are required');
307
        }
308
309
        $acl = $this->container->get('acl');
310
        $data['user'] = $acl->getUserId();
311
312
        return $this->createEntry('directus_preferences', $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createEntr...s_preferences', $data); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createPreferences of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
313
    }
314
315
    /**
316
     * @inheritdoc
317
     */
318
    public function createBookmark($data)
319
    {
320
        $acl = $this->container->get('acl');
321
        $data['user'] = $acl->getUserId();
322
323
        $preferences = $this->createPreferences(ArrayUtils::pick($data, [
324
            'title', 'table_name', 'sort', 'status', 'search_string', 'sort_order', 'columns_visible', 'user'
325
        ]));
326
327
        $title = $preferences->title;
0 ignored issues
show
Bug introduced by
The property title does not seem to exist in Directus\SDK\Response\EntryCollection.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
328
        $tableName = $preferences->table_name;
0 ignored issues
show
Bug introduced by
The property table_name does not seem to exist in Directus\SDK\Response\EntryCollection.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
329
        $bookmarkData = [
330
            'section' => 'search',
331
            'title' => $title,
332
            'url' => 'tables/' . $tableName . '/pref/' . $title,
333
            'user' => $data['user']
334
        ];
335
336
        return $this->createEntry('directus_bookmarks', $bookmarkData);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createEntr...marks', $bookmarkData); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createBookmark of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
337
    }
338
339
    /**
340
     * @inheritdoc
341
     */
342
    public function createColumn($data)
343
    {
344
        $data = $this->parseColumnData($data);
345
346
        $tableGateway = $this->getTableGateway($data['table_name']);
347
348
        $tableGateway->addColumn($data['table_name'], ArrayUtils::omit($data, ['table_name']));
349
350
        return $this->getColumn($data['table_name'], $data['column_name']);
351
    }
352
353
    /**
354
     * @inheritdoc
355
     */
356
    public function createGroup(array $data)
357
    {
358
        return $this->createEntry('directus_groups', $data);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this->createEntr...rectus_groups', $data); (Directus\SDK\Response\EntryCollection) is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createGroup of type Directus\SDK\Response\Entry.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
359
    }
360
361
    /**
362
     * @inheritdoc
363
     */
364
    public function createMessage(array $data)
365
    {
366
        $this->requiredAttributes(['from', 'message', 'subject'], $data);
367
        $this->requiredOneAttribute(['to', 'toGroup'], $data);
368
369
        $recipients = $this->getMessagesTo($data);
370
        $recipients = explode(',', $recipients);
371
        ArrayUtils::remove($data, ['to', 'toGroup']);
372
373
        $groupRecipients = [];
374
        $userRecipients = [];
375
        foreach ($recipients as $recipient) {
376
            $typeAndId = explode('_', $recipient);
377
            if ($typeAndId[0] == 0) {
378
                $userRecipients[] = $typeAndId[1];
379
            } else {
380
                $groupRecipients[] = $typeAndId[1];
381
            }
382
        }
383
384
        $ZendDb = $this->container->get('connection');
385
        $acl = $this->container->get('acl');
386
        if (count($groupRecipients) > 0) {
387
            $usersTableGateway = new DirectusUsersTableGateway($ZendDb, $acl);
388
            $result = $usersTableGateway->findActiveUserIdsByGroupIds($groupRecipients);
389
            foreach ($result as $item) {
390
                $userRecipients[] = $item['id'];
391
            }
392
        }
393
394
        $userRecipients[] = $acl->getUserId();
395
396
        $messagesTableGateway = new DirectusMessagesTableGateway($ZendDb, $acl);
397
        $id = $messagesTableGateway->sendMessage($data, array_unique($userRecipients), $acl->getUserId());
398
399
        if ($id) {
400
            $Activity = new DirectusActivityTableGateway($ZendDb, $acl);
401
            $data['id'] = $id;
402
            $Activity->recordMessage($data, $acl->getUserId());
403
        }
404
405
        $message = $messagesTableGateway->fetchMessageWithRecipients($id, $acl->getUserId());
406
        $response = [
407
            'meta' => [
408
                'type' => 'entry',
409
                'table' => 'directus_messages'
410
            ],
411
            'data' => $message
412
        ];
413
414
        return $this->createResponseFromData($response);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFromData($response); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 414 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createMessage of type Directus\SDK\Response\Entry.
Loading history...
415
    }
416
417
    /**
418
     * @inheritdoc
419
     */
420
    public function sendMessage(array $data)
421
    {
422
        return $this->createMessage($data);
423
    }
424
425
    public function createPrivileges(array $data)
426
    {
427
        $connection = $this->container->get('connection');
428
        $acl = $this->container->get('acl');
429
        $privileges = new DirectusPrivilegesTableGateway($connection, $acl);
430
431
        $response = [
432
            'meta' => [
433
                'type' => 'entry',
434
                'table' => 'directus_privileges'
435
            ],
436
            'data' => $privileges->insertPrivilege($data)
437
        ];
438
439
        return $this->createResponseFromData($response);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFromData($response); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 439 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createPrivileges of type Directus\SDK\Response\Entry.
Loading history...
440
    }
441
442
    public function createTable($name, array $data = [])
443
    {
444
        $isTableNameAlphanumeric = preg_match("/[a-z0-9]+/i", $name);
445
        $zeroOrMoreUnderscoresDashes = preg_match("/[_-]*/i", $name);
446
447
        if (!($isTableNameAlphanumeric && $zeroOrMoreUnderscoresDashes)) {
448
            return $this->createResponseFromData(['error' => ['message' => 'invalid_table_name']]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->createResponseFro...invalid_table_name'))); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 448 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createTable of type Directus\SDK\Response\Entry.
Loading history...
449
        }
450
451
        $schema = $this->container->get('schemaManager');
452
        $emitter = $this->container->get('emitter');
453
        if (!$schema->tableExists($name)) {
454
            $emitter->run('table.create:before', $name);
455
            // Through API:
456
            // Remove spaces and symbols from table name
457
            // And in lowercase
458
            $name = SchemaUtils::cleanTableName($name);
459
            $schema->createTable($name);
460
            $emitter->run('table.create', $name);
461
            $emitter->run('table.create:after', $name);
462
        }
463
464
        $connection = $this->container->get('connection');
465
        $acl = $this->container->get('acl');
466
        $privileges = new DirectusPrivilegesTableGateway($connection, $acl);
467
468
        return $this->createResponseFromData($privileges->insertPrivilege([
1 ignored issue
show
Bug Compatibility introduced by
The expression $this->createResponseFro...able_name' => $name))); of type Directus\SDK\Response\En...ctus\SDK\Response\Entry adds the type Directus\SDK\Response\EntryCollection to the return on line 468 which is incompatible with the return type declared by the interface Directus\SDK\RequestsInterface::createTable of type Directus\SDK\Response\Entry.
Loading history...
469
            'group_id' => 1,
470
            'table_name' => $name
471
        ]));
472
    }
473
474
    /**
475
     * Get a table gateway for the given table name
476
     *
477
     * @param $tableName
478
     *
479
     * @return RelationalTableGateway
480
     */
481
    protected function getTableGateway($tableName)
482
    {
483
        if (!array_key_exists($tableName, $this->tableGateways)) {
484
            $acl = TableSchema::getAclInstance();
485
            $this->tableGateways[$tableName] = new RelationalTableGateway($tableName, $this->connection, $acl);
486
        }
487
488
        return $this->tableGateways[$tableName];
489
    }
490
}
491