Completed
Push — master ( 805de4...131e3d )
by Vitaly
02:35
created

CMS::init()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 29 and the first side effect is on line 5.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
namespace samsoncms\api;
3
4
// Backward compatibility
5 1
require('generated/Material.php');
6 1
require('generated/Field.php');
7 1
require('generated/MaterialField.php');
8 1
require('generated/Structure.php');
9 1
require('generated/StructureField.php');
10
11
use samsoncms\api\generator\analyzer\Virtual;
12
use samsoncms\api\generator\Collection;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, samsoncms\api\Collection.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
13
use samsoncms\api\generator\Entity;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, samsoncms\api\Entity.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
14
use samsoncms\api\generator\Gallery;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, samsoncms\api\Gallery.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
15
use samsoncms\api\generator\Query;
16
17
use samsoncms\api\generator\Writer;
18
use samsonframework\core\ResourcesInterface;
19
use samsonframework\core\SystemInterface;
20
use samson\activerecord\TableRelation;
21
use samson\core\CompressableService;
22
use samson\activerecord\dbMySQLConnector;
23
use samsonphp\generator\Generator;
24
25
/**
26
 * SamsonCMS API
27
 * @package samsoncms\api
28
 */
29
class CMS extends CompressableService
0 ignored issues
show
Deprecated Code introduced by
The class samson\core\CompressableService has been deprecated with message: Just implement samsonframework\core\CompressInterface

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
30
{
31
    /** Database entity name for relations between material and navigation */
32
    const MATERIAL_NAVIGATION_RELATION_ENTITY = '\samson\activerecord\structurematerial';
33
    /** Database entity name for relations between material and images */
34
    const MATERIAL_IMAGES_RELATION_ENTITY = GalleryField::class;
35
    /** Database entity name for relations between additional fields and navigation */
36
    const FIELD_NAVIGATION_RELATION_ENTITY = '\samson\activerecord\structurefield';
37
    /** Database entity name for relations between material and additional fields values */
38
    const MATERIAL_FIELD_RELATION_ENTITY = MaterialField::class;
39
40
    /** Identifier */
41
    protected $id = 'cmsapi2';
42
43
    /** @var \samsonframework\orm\DatabaseInterface */
44
    protected $database;
45
46
    /** @var array[string] Collection of generated queries */
47
    protected $queries;
48
49
    /** @var string Database table names prefix */
50
    public $tablePrefix = '';
51
52
    /**
53
     * CMS constructor.
54
     *
55
     * @param string $path
56
     * @param ResourcesInterface $resources
57
     * @param SystemInterface $system
58
     */
59
    public function  __construct($path, ResourcesInterface $resources, SystemInterface $system)
0 ignored issues
show
Coding Style introduced by
Expected "function abc(...)"; found "function abc(...)"
Loading history...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 2 found
Loading history...
60
    {
61
        // TODO: This should changed to normal DI
62
        $this->database = db();
63
64
        parent::__construct($path, $resources, $system);
65
    }
66
67
    /**
68
     * Module initialization.
69
     *
70
     * @param array $params Initialization parameters
71
     * @return boolean|null Initialization result
72
     */
73
    public function init(array $params = array())
74
    {
75
        $this->rewriteEntityLocale();
76
    }
77
78
    public function beforeCompress(& $obj = null, array & $code = null)
79
    {
80
81
    }
82
83
    public function afterCompress(& $obj = null, array & $code = null)
84
    {
85
        // Iterate through generated php code
86
        $files = array();
87
        foreach (\samson\core\File::dir($this->cache_path, 'php', '', $files, 1) as $file) {
88
            // No namespace for global function file
89
            $ns = strpos($file, 'func') === false ? __NAMESPACE__ : '';
90
91
            // Compress generated php code
92
            $obj->compress_php($file, $this, $code, $ns);
93
        }
94
    }
95
96
    /**
97
     * Entity additional fields localization support.
98
     */
99
    protected function rewriteEntityLocale()
100
    {
101
        // Iterate all generated entity classes
102
        foreach (get_declared_classes() as $entityClass) {
103
            if (is_subclass_of($entityClass, '\samsoncms\api\Entity')) {
0 ignored issues
show
Bug introduced by
Due to PHP Bug #53727, is_subclass_of returns inconsistent results on some PHP versions for interfaces; you could instead use ReflectionClass::implementsInterface.
Loading history...
104
                // Insert current application locale
105
                str_replace('@locale', locale(), $entityClass::$_sql_select);
106
            }
107
        }
108
    }
109
110
    //[PHPCOMPRESSOR(remove,start)]
111
    /**
112
     * Read SQL file with variables placeholders pasting
113
     * @param string $filePath SQL file for reading
114
     * @param string $prefix Prefix for addition
115
     * @return array Collection of SQL command texts
116
     */
117
    public function readSQL($filePath, $prefix = '')
118
    {
119
        $sql = '';
120
121
        // Build path to SQL folder
122
        if (file_exists($filePath)) {
123
            // Replace prefix
124
            $sql = str_replace('@prefix', $prefix, file_get_contents($filePath));
125
        }
126
127
        // Split queries
128
        $sqlCommands = explode(';', str_replace("\n", '', $sql));
129
130
        // Always return array
131
        return array_filter(is_array($sqlCommands) ? $sqlCommands : array($sqlCommands));
132
    }
133
134
    /**
135
     * @see ModuleConnector::prepare()
136
     */
137
    public function prepare()
138
    {
139
        // Create cms_version
140
        $this->database->execute('
141
CREATE TABLE IF NOT EXISTS `cms_version`  (
142
  `version` varchar(15) NOT NULL DEFAULT \'30\'
143
) ENGINE=InnoDB DEFAULT CHARSET=utf8;'
144
        );
145
146
        // Perform this migration and execute only once
147
        if ($this->migrator() != 40) {
148
            // Perform SQL table creation
149
            $path = __DIR__ . '/../sql/';
150
            foreach (array_slice(scandir($path), 2) as $file) {
151
                trace('Performing database script ['.$file.']');
152
                foreach ($this->readSQL($path . $file, $this->tablePrefix) as $sql) {
153
                    $this->database->execute($sql);
154
                }
155
            }
156
            $this->migrator(40);
157
        }
158
159
        // Initiate migration mechanism
160
        $this->database->migration(get_class($this), array($this, 'migrator'));
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface samsonframework\orm\DatabaseInterface as the method migration() does only exist in the following implementations of said interface: samson\activerecord\dbMySQL.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
161
162
                // Define permanent table relations
163
        new TableRelation('material', 'user', 'UserID', 0, 'user_id');
164
        new TableRelation('material', 'gallery', 'MaterialID', TableRelation::T_ONE_TO_MANY);
165
        new TableRelation('material', 'materialfield', 'MaterialID', TableRelation::T_ONE_TO_MANY);
166
        new TableRelation('material', 'field', 'materialfield.FieldID', TableRelation::T_ONE_TO_MANY);
167
        new TableRelation('material', 'structurematerial', 'MaterialID', TableRelation::T_ONE_TO_MANY);
168
        new TableRelation('material', 'structure', 'structurematerial.StructureID', TableRelation::T_ONE_TO_MANY);
169
        new TableRelation('materialfield', 'field', 'FieldID');
170
        new TableRelation('materialfield', 'material', 'MaterialID');
171
        new TableRelation('structurematerial', 'structure', 'StructureID');
172
        new TableRelation('structurematerial', 'materialfield', 'MaterialID', TableRelation::T_ONE_TO_MANY);
173
        new TableRelation('structurematerial', 'material', 'MaterialID', TableRelation::T_ONE_TO_MANY);
174
        new TableRelation('structure', 'material', 'structurematerial.MaterialID', TableRelation::T_ONE_TO_MANY, null, 'manymaterials');
175
        new TableRelation('structure', 'gallery', 'structurematerial.MaterialID', TableRelation::T_ONE_TO_MANY, null, 'manymaterials');
176
        /*new TableRelation( 'structure', 'material', 'MaterialID' );*/
177
        new TableRelation('structure', 'user', 'UserID', 0, 'user_id');
178
        new TableRelation('structure', 'materialfield', 'material.MaterialID', TableRelation::T_ONE_TO_MANY, 'MaterialID', '_mf');
179
        new TableRelation('structure', 'structurematerial', 'StructureID', TableRelation::T_ONE_TO_MANY);
180
        //new TableRelation('related_materials', 'material', 'first_material', TableRelation::T_ONE_TO_MANY, 'MaterialID');
181
        //new TableRelation('related_materials', 'materialfield', 'first_material', TableRelation::T_ONE_TO_MANY, 'MaterialID');
182
        new TableRelation('field', 'structurefield', 'FieldID');
183
        new TableRelation('field', 'structure', 'structurefield.StructureID');
184
        new TableRelation('structurefield', 'field', 'FieldID');
185
        new TableRelation('structurefield', 'materialfield', 'FieldID');
186
        new TableRelation('structurefield', 'material', 'materialfield.MaterialID');
187
        new TableRelation('structure', 'structure_relation', 'StructureID', TableRelation::T_ONE_TO_MANY, 'parent_id', 'children_relations');
188
        new TableRelation('structure', 'structure', 'children_relations.child_id', TableRelation::T_ONE_TO_MANY, 'StructureID', 'children');
189
        new TableRelation('structure', 'structure_relation', 'StructureID', TableRelation::T_ONE_TO_MANY, 'child_id', 'parents_relations');
190
        new TableRelation('structure', 'structure', 'parents_relations.parent_id', TableRelation::T_ONE_TO_MANY, 'StructureID', 'parents');
191
        new TableRelation('structurematerial', 'structure_relation', 'StructureID', TableRelation::T_ONE_TO_MANY, 'parent_id');
192
        new TableRelation('groupright', 'right', 'RightID', TableRelation::T_ONE_TO_MANY);
193
194
        // TODO: Should be removed
195
        m('activerecord')->relations();
0 ignored issues
show
Deprecated Code introduced by
The function m() has been deprecated with message: Use $this->system->module() in module context

This function has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed from the class and what other function to use instead.

Loading history...
196
197
        $classWriter = new Writer(
198
            $this->database,
199
            new Generator(),
200
            __NAMESPACE__.'\\generated',
201
            [
202
                \samsoncms\api\generator\analyzer\Virtual::class => [
203
                    \samsoncms\api\generator\Entity::class,
204
                    \samsoncms\api\generator\Query::class,
205
                    \samsoncms\api\generator\Collection::class,
206
                ],
207
                \samsoncms\api\generator\analyzer\Gallery::class => [
208
                    \samsoncms\api\generator\Gallery::class,
209
                ],
210
                \samsoncms\api\generator\analyzer\Application::class => [
211
                    \samsoncms\api\generator\Application::class,
212
                    \samsoncms\api\generator\ApplicationCollection::class,
213
                ]
214
            ],
215
            $this->cache_path
216
        );
217
218
        $classWriter->write();
219
220
        return parent::prepare();
221
    }
222
223
    /**
224
     * Handler for CMSAPI database version manipulating
225
     * @param string $toVersion Version to switch to
226
     * @return string Current database version
227
     */
228
    public function migrator($toVersion = null)
229
    {
230
        // If something passed - change database version to it
231
        if (func_num_args()) {
232
            // Save current version to special db table
233
            $this->database->execute(
234
                "ALTER TABLE  `" . dbMySQLConnector::$prefix . "cms_version`
235
                CHANGE  `version`  `version` VARCHAR( 15 ) CHARACTER SET utf8
236
                COLLATE utf8_general_ci NOT NULL DEFAULT  '" . $toVersion . "';"
237
            );
238
            die('Database successfully migrated to [' . $toVersion . ']');
239
        } else { // Return current database version
240
            $version_row = $this->database->fetch('SHOW COLUMNS FROM `' . dbMySQLConnector::$prefix . 'cms_version`');
241
            if (isset($version_row[0]['Default'])) {
242
                return $version_row[0]['Default'];
243
            } else {
244
                return 0;
245
            }
246
        }
247
    }
248
    //[PHPCOMPRESSOR(remove,end)]
249
}
250