Completed
Pull Request — master (#10)
by
unknown
13:43 queued 01:20
created

YmlCatalog::getNewModel()   B

Complexity

Conditions 7
Paths 5

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 19
ccs 0
cts 0
cp 0
rs 8.2222
cc 7
eloc 14
nc 5
nop 1
crap 56
1
<?php
2
namespace pastuhov\ymlcatalog;
3
4
use pastuhov\ymlcatalog\models\BaseModel;
5
use pastuhov\ymlcatalog\models\Category;
6
use pastuhov\ymlcatalog\models\Currency;
7
use pastuhov\ymlcatalog\models\LocalDeliveryCost;
8
use pastuhov\ymlcatalog\models\Shop;
9
use pastuhov\ymlcatalog\models\SimpleOffer;
10
use Yii;
11
use pastuhov\FileStream\BaseFileStream;
12
use yii\base\Exception;
13
14
/**
15
 * Yml генератор каталога.
16
 *
17
 * @package pastuhov\ymlcatalog
18
 */
19
class YmlCatalog
20
{
21
    /**
22
     * @var BaseFileStream
23
     */
24
    protected $handle;
25
    /**
26
     * @var string
27
     */
28
    protected $shopClass;
29
    /**
30
     * @var string
31
     */
32
    protected $currencyClass;
33
    /**
34
     * @var string
35
     */
36
    protected $categoryClass;
37
    /**
38
     * @var string
39
     */
40
    protected $localDeliveryCostClass;
41
    /**
42
     * @var string
43
     */
44
    protected $offerClass;
45
    /**
46
     * @var null|string
47
     */
48
    protected $date;
49
50
    /**
51
     * @var null|callable
52
     */
53
    protected $onValidationError;
54
55
    /**
56
     * @var null|string
57
     */
58
    protected $customOfferClass;
59 6
60
    /**
61
     * @param BaseFileStream $handle
62
     * @param string $shopClass class name
63
     * @param string $currencyClass class name
64
     * @param string $categoryClass class name
65
     * @param string $localDeliveryCostClass class name
66
     * @param array $offerClasses
67
     * @param null|string $date
68 6
     * @param null|callable $onValidationError
69 6
     * @param null|string $customOfferClass
70 6
     */
71 6
    public function __construct(
72 6
        BaseFileStream $handle,
73 6
        $shopClass,
74 6
        $currencyClass,
75 6
        $categoryClass,
76
        $localDeliveryCostClass,
77
        Array $offerClasses,
78
        $date = null,
79
        $onValidationError = null,
80 6
        $customOfferClass = null
81
    ) {
82 6
        $this->handle = $handle;
83
        $this->shopClass = $shopClass;
84 6
        $this->currencyClass = $currencyClass;
85 6
        $this->categoryClass = $categoryClass;
86 6
        $this->localDeliveryCostClass = $localDeliveryCostClass;
87 6
        $this->offerClasses = $offerClasses;
0 ignored issues
show
Bug introduced by
The property offerClasses does not seem to exist. Did you mean offerClass?

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...
88 6
        $this->date = $date;
89
        $this->onValidationError = $onValidationError;
90 6
        $this->customOfferClass = $customOfferClass;
91 6
    }
92 6
93 6
    /**
94 6
     * @throws Exception
95 6
     */
96 6
    public function generate()
97 6
    {
98 6
        $date = $this->getDate();
99 6
100 6
        $this->write(
101 6
            '<?xml version="1.0" encoding="utf-8"?>' . PHP_EOL .
102 6
            '<!DOCTYPE yml_catalog SYSTEM "shops.dtd">' . PHP_EOL .
103 6
            '<yml_catalog date="' . $date . '">' . PHP_EOL
104 6
        );
105
106 6
        $this->writeTag('shop');
107 6
        $this->writeModel(new Shop(), new $this->shopClass());
108
        $this->writeTag('currencies');
109
        $this->writeEachModel($this->currencyClass);
110
        $this->writeTag('/currencies');
111
        $this->writeTag('categories');
112 6
        $this->writeEachModel($this->categoryClass);
113
        $this->writeTag('/categories');
114 6
        $this->writeModel(new LocalDeliveryCost(), new $this->localDeliveryCostClass());
115
        $this->writeTag('offers');
116 6
        foreach ($this->offerClasses as $offerClass) {
0 ignored issues
show
Bug introduced by
The property offerClasses does not seem to exist. Did you mean offerClass?

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...
117 3
            $this->writeEachModel($offerClass);
118 3
        }
119
        $this->writeTag('/offers');
120 6
        $this->writeTag('/shop');
121
122
        $this->write('</yml_catalog>');
123
    }
124
125
    /**
126
     * @return null|string
127 6
     */
128
    protected function getDate()
129 6
    {
130 6
        $date = $this->date;
131
132
        if ($date === null) {
133
            $date = Yii::$app->formatter->asDatetime(new \DateTime(), 'php:Y-m-d H:i');
134
        }
135 6
136
        return $date;
137 6
    }
138 6
139
    /**
140
     * @param string $string
141
     * @throws \Exception
142
     */
143
    protected function write($string)
144
    {
145 6
        $this->handle->write($string);
146
    }
147 6
148 6
    /**
149 6
     * @param string $string tag name
150 6
     */
151
    protected function writeTag($string)
152 6
    {
153 6
        $this->write('<' . $string . '>' . PHP_EOL);
154
    }
155 6
156 6
    /**
157 6
     * @param BaseModel $model model
158 6
     * @param $valuesModel
159 6
     * @throws Exception
160 6
     */
161 6
    protected function writeModel(BaseModel $model, $valuesModel)
162
    {
163 6
        $attributes = [];
164
        foreach ($model->attributes() as $attribute) {
165
            $methodName = 'get' . ucfirst($attribute);
166
            $attributeValue = $valuesModel->$methodName();
167 6
168
            $attributes[$attribute] = $attributeValue;
169 6
        }
170 6
171
        $model->load($attributes, '');
172
        if (method_exists($valuesModel, 'getParams')) {
173
            $model->setParams($valuesModel->getParams());
174
        }
175 6
        if (method_exists($valuesModel, 'getPictures')) {
176
            $model->setPictures($valuesModel->getPictures());
177 6
        }
178
179
        if (!$model->validate()) {
180 6
            if (is_callable($onValidationError = $this->onValidationError)) {
181
                $onValidationError($model);
182 6
            } else {
183 6
                throw new Exception('Model values is invalid ' . serialize($model->getErrors()));
184 6
            }
185 6
        } else {
186 6
            $string = $model->getYml();
187 6
188
            $this->write($string);
189
        }
190
    }
191
192
    /**
193
     * @param string|array $modelClass class name
194 6
     */
195
    protected function writeEachModel($modelClass)
196 6
    {
197
        $class = isset($modelClass['class']) ? $modelClass['class'] : $modelClass;
198 6
        $findParams = isset($modelClass['findParams']) ? $modelClass['findParams'] : [];
199 6
200 6
        $newModel = $this->getNewModel($class);
201 6
202 6
        /* @var \yii\db\ActiveQuery $query */
203 6
        $query = $class::findYml($findParams);
204 6
205
        foreach ($query->batch(100) as $models) {
206
            foreach ($models as $model) {
207
                $this->writeModel($newModel, $model);
208 6
            }
209
        }
210
    }
211
212
    /**
213
     * @param $modelClass
214
     * @return Category|Currency|SimpleOffer
215
     * @throws Exception
216
     */
217
    protected function getNewModel($modelClass)
218
    {
219
        $obj = new $modelClass();
220
221
        if ($obj instanceof CurrencyInterface) {
222
            $model = new Currency();
223
        } elseif ($obj instanceof CategoryInterface) {
224
            $model = new Category();
225
        } elseif ($obj instanceof CustomOfferInterface && $this->customOfferClass !== null && class_exists($this->customOfferClass)) {
226
            $class = $this->customOfferClass;
227
            $model = new $class();
228
        } elseif ($obj instanceof SimpleOfferInterface) {
229
            $model = new SimpleOffer();
230
        } else {
231
            throw new Exception('Model ' . $modelClass. ' has unknown interface');
232
        }
233
234
        return $model;
235
    }
236
}
237