NOSQLService::init()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 2
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
nc 1
nop 0
1
<?php
2
namespace NOSQL\Services;
3
4
use MongoDB\Database;
5
use MongoDB\Model\BSONDocument;
6
use NOSQL\Dto\CollectionDto;
7
use NOSQL\Dto\Validation\EnumPropertyDto;
8
use NOSQL\Dto\Validation\JsonSchemaDto;
9
use NOSQL\Dto\Validation\NumberPropertyDto;
10
use NOSQL\Dto\Validation\StringPropertyDto;
11
use NOSQL\Services\Base\NOSQLBase;
12
use PSFS\base\Cache;
13
use PSFS\base\config\Config;
14
use PSFS\base\dto\Field;
15
use PSFS\base\exception\ApiException;
16
use PSFS\base\Logger;
17
use PSFS\base\Router;
18
use PSFS\base\Service;
19
use PSFS\base\Template;
20
use PSFS\base\types\helpers\GeneratorHelper;
21
use PSFS\base\types\helpers\RouterHelper;
22
23
/**
24
* Class NOSQLService
25
* @package NOSQL\Services
26
* @author Fran López <[email protected]>
27
* @version 1.0
28
* Autogenerated service [2019-01-03 15:23:58]
29
*/
30
class NOSQLService extends Service {
31
32
    /**
33
     * @Injectable
34
     * @var \PSFS\base\Cache
35
     */
36
    protected $cache;
37
38
    /**
39
     * @var array
40
     */
41
    private $types = [];
42
43
    /**
44
     * @return array
45
     */
46
    public function getTypes()
47
    {
48
        return $this->types;
49
    }
50
51
    /**
52
     * @param array $types
53
     */
54
    public function setTypes($types)
55
    {
56
        $this->types = $types;
57
    }
58
59
    /**
60
     * @throws \ReflectionException
61
     */
62
    private function extractTypes() {
63
        $baseClass = new \ReflectionClass(NOSQLBase::class);
64
        if(null !== $baseClass) {
65
            $types = [];
66
            foreach($baseClass->getConstants() as $constant) {
67
                $types[] = $constant;
68
            }
69
            $this->setTypes($types);
70
        }
71
    }
72
73
    /**
74
     * @throws \ReflectionException
75
     */
76
    public function init()
77
    {
78
        parent::init();
79
        $this->extractTypes();
80
    }
81
82
    /**
83
     * @return array
84
     */
85
    public function getDomains() {
86
        $domains = [];
87
        $storedDomains = $this->cache->getDataFromFile(CONFIG_DIR . DIRECTORY_SEPARATOR . 'domains.json', Cache::JSON, TRUE);
88
        if(!empty($storedDomains)) {
89
            foreach($storedDomains as $domain => $data) {
90
                $domainLabel = str_replace(['@', '/'], '', $domain);
91
                if('ROOT' !== $domainLabel) {
92
                    $domains[] = $domainLabel;
93
                }
94
            }
95
        }
96
        return $domains;
97
    }
98
99
    public static function getDomainPaths($module) {
100
        $domains = Router::getInstance()->getDomains();
101
        $path = null;
102
        foreach($domains as $domain => $paths) {
103
            if(preg_match("/^@" . $module . "\//i", $domain)) {
104
                $path = $paths;
105
                break;
106
            }
107
        }
108
        return $path;
109
    }
110
111
    /**
112
     * @param string $module
113
     * @return array
114
     */
115
    public function getCollections($module) {
116
        $collections = [];
117
        $path = self::getDomainPaths($module);
118
        if(null === $path) {
119
            throw new ApiException(t("Module not found"), 404);
120
        }
121
        $schemaFilename = $path['base'] . 'Config' . DIRECTORY_SEPARATOR . 'schema.json';
122
        if(file_exists($schemaFilename)) {
123
            $collections = $this->cache->getDataFromFile($schemaFilename, Cache::JSON, TRUE);
124
        }
125
        return $collections;
126
    }
127
128
    /**
129
     * @param string $module
130
     * @param array $collections
131
     * @throws \PSFS\base\exception\GeneratorException
132
     */
133
    public function setCollections($module, $collections) {
134
        $schemaFilename = CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Config' . DIRECTORY_SEPARATOR . 'schema.json';
135
        $this->cache->storeData($schemaFilename, $collections, Cache::JSON, true);
136
        $tpl = Template::getInstance();
137
        $tpl->addPath(__DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Templates', 'NOSQL');
138
        $files = [
139
            '@NOSQL/generator/model.base.php.twig' => CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Models' . DIRECTORY_SEPARATOR . 'Base',
140
            '@NOSQL/generator/model.php.twig' => CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Models',
141
            '@NOSQL/generator/api.php.twig' => CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Api',
142
            '@NOSQL/generator/api.base.php.twig' => CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Api' . DIRECTORY_SEPARATOR . 'Base',
143
            '@NOSQL/generator/dto.php.twig' => CORE_DIR . DIRECTORY_SEPARATOR . $module . DIRECTORY_SEPARATOR . 'Dto' . DIRECTORY_SEPARATOR . 'Models',
144
        ];
145
        foreach($collections as $raw) {
146
            $collection = new CollectionDto(false);
147
            $collection->fromArray($raw);
148
            foreach($files as $template => $path) {
149
                GeneratorHelper::createDir($path);
150
                $templateDump = $tpl->dump($template, [
151
                    'domain' => $module,
152
                    'model' => $collection->name,
153
                    'properties' => $collection->properties,
154
                    'indexes' => $collection->indexes,
155
                ]);
156
                $force = false;
157
                if(false !== strpos($template, 'dto') || false !== strpos(strtolower($template), 'base')) {
158
                    $force = true;
159
                }
160
                $this->writeTemplateToFile($templateDump, $path . DIRECTORY_SEPARATOR . $collection->name . '.php', $force);
161
            }
162
        }
163
    }
164
165
    /**
166
     * @param string $fileContent
167
     * @param string $filename
168
     * @param bool $force
169
     * @return bool
170
     */
171
    private function writeTemplateToFile($fileContent, $filename, $force = false)
172
    {
173
        $created = false;
174
        if ($force || !file_exists($filename)) {
175
            try {
176
                $this->cache->storeData($filename, $fileContent, Cache::TEXT, true);
177
                $created = true;
178
            } catch (\Exception $e) {
179
                Logger::log($e->getMessage(), LOG_ERR);
180
            }
181
        } else {
182
            Logger::log($filename . t(' not exists or cant write'), LOG_ERR);
183
        }
184
        return $created;
185
    }
186
187
    /**
188
     * @param Database $db
189
     * @param $collectionDto
190
     */
191
    private function createTextIndex(Database $db, $collectionDto) {
192
        try {
193
            $textIndexes = [];
194
            foreach($collectionDto['properties'] as $property) {
195
                if(in_array($property['type'], [NOSQLBase::NOSQL_TYPE_STRING, NOSQLBase::NOSQL_TYPE_OBJECT])) {
196
                    $textIndexes[$property['name']] = 'text';
197
                }
198
            }
199
            if(count($textIndexes)) {
200
                $collection = $db->selectCollection($collectionDto['name']);
201
                $collection->createIndex($textIndexes, ['name' => 'idx_text_' . $collectionDto['name']]);
202
            }
203
        } catch (\Exception $exception) {
204
            Logger::log($exception->getMessage(), LOG_DEBUG);
205
        }
206
    }
207
208
    /**
209
     * @param Database $db
210
     * @param $collectionDto
211
     * @param array $indexes
212
     * @param array $options
213
     */
214
    private function createIndexes(Database $db, $collectionDto, array $indexes = []) {
215
        try {
216
            $collection = $db->selectCollection($collectionDto['name']);
217
            if(count($indexes)) {
218
                $collection->createIndexes($indexes);
219
            }
220
        } catch (\Exception $exception) {
221
            Logger::log($exception->getMessage(), LOG_DEBUG);
222
        }
223
    }
224
225
    /**
226
     * @param $module
227
     * @return bool
228
     * @throws \PSFS\base\exception\GeneratorException
229
     */
230
    public function syncCollections($module) {
231
        $db = ParserService::getInstance()->createConnection($module);
232
        $collections = $this->getCollections($module);
233
        $success = true;
234
        foreach($collections as $raw) {
235
            $jsonSchema = $this->parseCollection($raw);
236
            try {
237
                /** @var BSONDocument $result */
238
                $result = $db->createCollection($raw['name'], [
239
                    'validation' => [
240
                        '$jsonSchema' => $jsonSchema->toArray(),
241
                    ]
242
                ]);
243
                $response = $result->getArrayCopy();
244
                $success = array_key_exists('ok', $response) && $response['ok'] > 0;
245
            } catch(\Exception $exception) {
246
                if($exception->getCode() !== 48) {
247
                    $success = false;
248
                }
249
            }
250
            if($success) {
251
                if (Config::getParam("nosql.sync.defaultIndex", false, $module)) {
252
                    $this->createTextIndex($db, $raw);
253
                }
254
                $indexToCreate = [];
255
                foreach($raw['indexes'] as $index) {
256
                    $dbIndex = [];
257
                    foreach($index['properties'] as $idx) {
258
                        list($property, $direction) = explode('.', $idx);
259
                        switch(strtoupper($direction)) {
260
                            case 'ASC': $dbIndex[$property] = 1; break;
261
                            case 'DESC': $dbIndex[$property] = -1; break;
262
                        }
263
                    }
264
                    $indexToCreate[] = [
265
                        'key' => $dbIndex,
266
                        'name' => $index['name'],
267
                        'unique' => $index['unique'],
268
                    ];
269
                }
270
                $this->createIndexes($db, $raw, $indexToCreate);
271
            }
272
273
        }
274
        return $success;
275
    }
276
277
    /**
278
     * @param array $raw
279
     * @return JsonSchemaDto
280
     * @throws \PSFS\base\exception\GeneratorException
281
     */
282
    private function parseCollection($raw)
283
    {
284
        $jsonSchema = new JsonSchemaDto(false);
285
        foreach ($raw['properties'] as $rawProperty) {
286
            switch ($rawProperty['type']) {
287
                case NOSQLBase::NOSQL_TYPE_INTEGER:
288
                case NOSQLBase::NOSQL_TYPE_DOUBLE:
289
                case NOSQLBase::NOSQL_TYPE_LONG:
290
                    $property = new NumberPropertyDto(false);
291
                    break;
292
                case NOSQLBase::NOSQL_TYPE_ENUM:
293
                    $property = new EnumPropertyDto(false);
294
                    $property->enum = explode('|', $rawProperty['enum']);
295
                    break;
296
                default:
297
                    $property = new StringPropertyDto(false);
298
                    break;
299
            }
300
            if(array_key_exists('type', $rawProperty)) {
301
                $property->bsonType = $rawProperty['type'];
302
            }
303
            if(array_key_exists('description', $rawProperty)) {
304
                $property->description = $rawProperty['description'];
305
            }
306
            if (array_key_exists('required', $rawProperty) && $rawProperty['required']) {
307
                $jsonSchema->required[] = $rawProperty['name'];
308
            }
309
            $jsonSchema->properties[$rawProperty['name']] = $property->toArray();
310
        }
311
        return $jsonSchema;
312
    }
313
314
    /**
315
     * @return array
316
     * @throws \ReflectionException
317
     */
318
    public function getValidations() {
319
        $fieldTypes = new \ReflectionClass(Field::class);
320
        $validations = [];
321
        foreach($fieldTypes->getConstants() as $validation) {
322
            $validations[] = $validation;
323
        }
324
        return $validations;
325
    }
326
}
327