Passed
Push — master ( c12552...22ad80 )
by Gabor
04:56
created

FilesystemStorage::populateEntity()   C

Complexity

Conditions 9
Paths 1

Size

Total Lines 22
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 0
loc 22
ccs 0
cts 21
cp 0
rs 6.412
c 0
b 0
f 0
cc 9
eloc 19
nc 1
nop 2
crap 90
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 7.1
6
 *
7
 * @copyright 2012 - 2017 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
declare(strict_types = 1);
13
14
namespace WebHemi\Data\Storage\Filesystem;
15
16
use WebHemi\DateTime;
17
use WebHemi\Data\ConnectorInterface;
18
use WebHemi\Data\EntityInterface;
19
use WebHemi\Data\Storage\AbstractStorage;
20
use WebHemi\Data\Entity\Filesystem\FilesystemEntity;
21
22
/**
23
 * Class FilesystemStorage.
24
 */
25
class FilesystemStorage extends AbstractStorage
26
{
27
    public const TYPE_DOCUMENT = FilesystemEntity::TYPE_DOCUMENT;
28
    public const TYPE_BINARY = FilesystemEntity::TYPE_BINARY;
29
    public const TYPE_DIRECTORY = FilesystemEntity::TYPE_DIRECTORY;
30
    public const TYPE_SYMLINK = FilesystemEntity::TYPE_SYMLINK;
31
32
    /** @var string */
33
    protected $dataGroup = 'webhemi_filesystem';
34
    /** @var string */
35
    protected $idKey = 'id_filesystem';
36
    /** @var string */
37
    private $idApplication = 'fk_application';
38
    /** @var string */
39
    private $idCategory = 'fk_category';
40
    /** @var string */
41
    private $idParent = 'fk_parent_node';
42
    /** @var string */
43
    private $idDocument = 'fk_filesystem_document';
44
    /** @var string */
45
    private $idFile = 'fk_filesystem_file';
46
    /** @var string */
47
    private $idDirectory = 'fk_filesystem_directory';
48
    /** @var string */
49
    private $idLink = 'fk_filesystem_link';
50
    /** @var string */
51
    private $path = 'path';
52
    /** @var string */
53
    private $baseName = 'basename';
54
    /** @var string */
55
    private $title = 'title';
56
    /** @var string */
57
    private $description = 'description';
58
    /** @var string */
59
    private $isHidden = 'is_hidden';
60
    /** @var string */
61
    private $isReadOnly = 'is_read_only';
62
    /** @var string */
63
    private $isDeleted = 'is_deleted';
64
    /** @var string */
65
    private $dateCreated = 'date_created';
66
    /** @var string */
67
    private $dateModified = 'date_modified';
68
    /** @var string */
69
    private $datePublished = 'date_published';
70
71
    /**
72
     * Populates an entity with storage data.
73
     *
74
     * @param EntityInterface $dataEntity
75
     * @param array           $data
76
     * @return void
77
     */
78
    protected function populateEntity(EntityInterface&$dataEntity, array $data) : void
79
    {
80
        /* @var FilesystemEntity $dataEntity */
81
        $dataEntity->setFilesystemId((int) $data[$this->idKey])
82
            ->setApplicationId((int) $data[$this->idApplication])
83
            ->setCategoryId(isset($data[$this->idCategory]) ? (int)$data[$this->idCategory] : null)
84
            ->setParentId(isset($data[$this->idParent]) ? (int)$data[$this->idParent] : null)
85
            ->setDocumentId(isset($data[$this->idDocument]) ? (int)$data[$this->idDocument] : null)
86
            ->setFileId(isset($data[$this->idFile]) ? (int)$data[$this->idFile] : null)
87
            ->setDirectoryId(isset($data[$this->idDirectory]) ? (int)$data[$this->idDirectory] : null)
88
            ->setLinkId(isset($data[$this->idLink]) ? (int)$data[$this->idLink] : null)
89
            ->setPath($data[$this->path])
90
            ->setBaseName($data[$this->baseName])
91
            ->setTitle($data[$this->title])
92
            ->setDescription($data[$this->description])
93
            ->setHidden((bool) $data[$this->isHidden])
94
            ->setReadOnly((bool) $data[$this->isReadOnly])
95
            ->setDeleted((bool) $data[$this->isDeleted])
96
            ->setDateCreated(new DateTime($data[$this->dateCreated] ?? 'now'))
97
            ->setDateModified(!empty($data[$this->dateModified]) ? new DateTime($data[$this->dateModified]) : null)
0 ignored issues
show
Bug introduced by
It seems like !empty($data[$this->date...->dateModified]) : null can be null; however, setDateModified() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
98
            ->setDatePublished(!empty($data[$this->datePublished]) ? new DateTime($data[$this->datePublished]) : null);
0 ignored issues
show
Bug introduced by
It seems like !empty($data[$this->date...>datePublished]) : null can be null; however, setDatePublished() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
99
    }
100
101
    /**
102
     * Get data from an entity.
103
     *
104
     * @param EntityInterface $dataEntity
105
     * @return array
106
     */
107
    protected function getEntityData(EntityInterface $dataEntity) : array
108
    {
109
        /** @var FilesystemEntity $dataEntity */
110
        $dateCreated = $dataEntity->getDateCreated();
111
        $dateModified = $dataEntity->getDateModified();
112
        $datePublished = $dataEntity->getDatePublished();
113
114
        return [
115
            $this->idKey => $dataEntity->getKeyData(),
116
            $this->idApplication = $dataEntity->getApplicationId(),
0 ignored issues
show
Documentation Bug introduced by
It seems like $dataEntity->getApplicationId() can also be of type integer. However, the property $idApplication is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
117
            $this->idCategory = $dataEntity->getCategoryId(),
0 ignored issues
show
Documentation Bug introduced by
It seems like $dataEntity->getCategoryId() can also be of type integer. However, the property $idCategory is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
118
            $this->idParent = $dataEntity->getParentId(),
0 ignored issues
show
Documentation Bug introduced by
It seems like $dataEntity->getParentId() can also be of type integer. However, the property $idParent is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
119
            $this->documentId = $dataEntity->getDocumentId(),
0 ignored issues
show
Bug introduced by
The property documentId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
120
            $this->fileId = $dataEntity->getFileId(),
0 ignored issues
show
Bug introduced by
The property fileId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
121
            $this->directoryId = $dataEntity->getDirectoryId(),
0 ignored issues
show
Bug introduced by
The property directoryId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
122
            $this->linkId = $dataEntity->getLinkId(),
0 ignored issues
show
Bug introduced by
The property linkId does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
123
            $this->path => $dataEntity->getPath(),
124
            $this->baseName => $dataEntity->getBaseName(),
125
            $this->title => $dataEntity->getTitle(),
126
            $this->description => $dataEntity->getDescription(),
127
            $this->isHidden => (int) $dataEntity->getHidden(),
128
            $this->isReadOnly => (int) $dataEntity->getReadOnly(),
129
            $this->isDeleted => (int) $dataEntity->getDeleted(),
130
            $this->dateCreated => $dateCreated instanceof DateTime ? $dateCreated->format('Y-m-d H:i:s') : null,
131
            $this->dateModified => $dateModified instanceof DateTime ? $dateModified->format('Y-m-d H:i:s') : null,
132
            $this->datePublished => $datePublished instanceof DateTime ? $datePublished->format('Y-m-d H:i:s') : null
133
        ];
134
    }
135
136
    /**
137
     * Gets the filesystem entity by the identifier.
138
     *
139
     * @param int $identifier
140
     * @return null|FilesystemEntity
141
     */
142
    public function getFilesystemById(int $identifier) : ? FilesystemEntity
143
    {
144
        /** @var null|FilesystemEntity $dataEntity */
145
        $dataEntity = $this->getDataEntity([$this->idKey => $identifier]);
146
147
        return $dataEntity;
148
    }
149
150
    /**
151
     * Gets the filesystem entity by custom expression.
152
     *
153
     * @param int $applicationId
154
     * @param int $directoryId
155
     * @return FilesystemEntity[]
156
     */
157
    public function getFilesystemSetByApplicationAndDirectory(int $applicationId, int $directoryId) : ? array
158
    {
159
        /** @var FilesystemEntity[] $dataEntitySet */
160
        $dataEntitySet = $this->getDataEntitySet(
161
            [$this->idApplication => $applicationId, $this->idDirectory => $directoryId]
162
        );
163
164
        return $dataEntitySet;
165
    }
166
167
    /**
168
     * Gets the filesystem entity according to the application and the uri.
169
     *
170
     * @param int $applicationId
171
     * @param string $path
172
     * @param string $baseName
173
     * @return null|FilesystemEntity
174
     */
175
    public function getFilesystemData(int $applicationId, string $path, string $baseName) : ? FilesystemEntity
176
    {
177
        /** @var null|FilesystemEntity $dataEntity */
178
        $dataEntity = $this->getDataEntity(
179
            [
180
                $this->idApplication => $applicationId,
181
                $this->path => $path,
182
                $this->baseName => $baseName
183
            ]
184
        );
185
186
        return $dataEntity;
187
    }
188
189
    /**
190
     * Gets the published documents
191
     *
192
     * @param int $applicationId
193
     * @param array $additionalExpressions
194
     * @param string|null $order
195
     * @param int|null $limit
196
     * @param int|null $offset
197
     * @param string|null $groupBy
198
     * @param string|null $having
199
     * @return FilesystemEntity[]
200
     */
201
    public function getPublishedDocuments(
202
        int $applicationId,
203
        array $additionalExpressions = [],
204
        string $order = null,
205
        int $limit = null,
206
        int $offset = null,
207
        string $groupBy = null,
208
        string $having = null
209
    ) : array {
210
        $defaultExpressions = [
211
            $this->idApplication => $applicationId,
212
            $this->isHidden => 0,
213
            $this->isDeleted => 0,
214
            $this->datePublished => true, // >> IS NOT NULL
215
            $this->idDocument => true // >> will get documents only
216
        ];
217
218
        // This way the default ones can be overwritten.
219
        $expressions = array_merge($defaultExpressions, $additionalExpressions);
220
221
        $options = [
222
            ConnectorInterface::OPTION_ORDER => ($order ?? $this->datePublished.' DESC')
223
        ];
224
225
        if (is_numeric($limit)) {
226
            $options[ConnectorInterface::OPTION_LIMIT] = (int) $limit;
227
228
            if (is_numeric($offset)) {
229
                $options[ConnectorInterface::OPTION_OFFSET] = (int) $offset;
230
            }
231
        }
232
233
        if (!empty($groupBy)) {
234
            $options[ConnectorInterface::OPTION_GROUP] = $groupBy;
235
236
            if (!empty($having)) {
237
                $options[ConnectorInterface::OPTION_HAVING] = $having;
238
            }
239
        }
240
241
        /** @var FilesystemEntity[] $dataEntitySet */
242
        $dataEntitySet = $this->getDataEntitySet($expressions, $options);
243
244
        return $dataEntitySet;
245
    }
246
247
    /**
248
     * Gets simple structured meta information for a filesystem record.
249
     *
250
     * @param int $filesystemId
251
     * @return array
252
     */
253
    public function getPublicationMeta(int $filesystemId) : array
254
    {
255
        $filesystemMetaSet = [];
256
257
        /** @var ConnectorInterface $connector */
258
        $connector = $this->getConnector();
259
260
        // Switch to another data group (DO NOT FORGET TO SET IT BACK!!)
261
        $connector->setDataGroup('webhemi_filesystem_meta')
262
            ->setIdKey('id_filesystem_meta');
263
264
        $filesystemRecord = $connector->getDataSet(['fk_filesystem' => $filesystemId]);
265
266
        // switch back to the original data group
267
        $connector->setDataGroup($this->dataGroup)
268
            ->setIdKey($this->idKey);
269
270
        foreach ($filesystemRecord as $data) {
271
            $filesystemMetaSet[$data['meta_key']] = $data['meta_data'];
272
        }
273
274
        return $filesystemMetaSet;
275
    }
276
}
277