Completed
Pull Request — master (#9)
by
unknown
14:11
created

YmlCatalog::writeEachModel()   B

Complexity

Conditions 5
Paths 12

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 5

Importance

Changes 4
Bugs 0 Features 1
Metric Value
c 4
b 0
f 1
dl 0
loc 16
ccs 8
cts 8
cp 1
rs 8.8571
cc 5
eloc 8
nc 12
nop 1
crap 5
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
     * @param BaseFileStream $handle
57
     * @param string $shopClass class name
58
     * @param string $currencyClass class name
59 6
     * @param string $categoryClass class name
60
     * @param string $localDeliveryCostClass class name
61
     * @param array $offerClasses
62
     * @param null|string $date
63
     * @param null|callable $onValidationError
64
     */
65
    public function __construct(
66
        BaseFileStream $handle,
67
        $shopClass,
68 6
        $currencyClass,
69 6
        $categoryClass,
70 6
        $localDeliveryCostClass,
71 6
        Array $offerClasses,
72 6
        $date = null,
73 6
        $onValidationError = null
74 6
    ) {
75 6
        $this->handle = $handle;
76
        $this->shopClass = $shopClass;
77
        $this->currencyClass = $currencyClass;
78
        $this->categoryClass = $categoryClass;
79
        $this->localDeliveryCostClass = $localDeliveryCostClass;
80 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...
81
        $this->date = $date;
82 6
        $this->onValidationError = $onValidationError;
83
    }
84 6
85 6
    /**
86 6
     * @throws Exception
87 6
     */
88 6
    public function generate()
89
    {
90 6
        $date = $this->getDate();
91 6
92 6
        $this->write(
93 6
            '<?xml version="1.0" encoding="utf-8"?>' . PHP_EOL .
94 6
            '<!DOCTYPE yml_catalog SYSTEM "shops.dtd">' . PHP_EOL .
95 6
            '<yml_catalog date="' . $date . '">' . PHP_EOL
96 6
        );
97 6
98 6
        $this->writeTag('shop');
99 6
        $this->writeModel(new Shop(), new $this->shopClass());
100 6
        $this->writeTag('currencies');
101 6
        $this->writeEachModel($this->currencyClass);
102 6
        $this->writeTag('/currencies');
103 6
        $this->writeTag('categories');
104 6
        $this->writeEachModel($this->categoryClass);
105
        $this->writeTag('/categories');
106 6
        $this->writeModel(new LocalDeliveryCost(), new $this->localDeliveryCostClass());
107 6
        $this->writeTag('offers');
108
        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...
109
            $this->writeEachModel($offerClass);
110
        }
111
        $this->writeTag('/offers');
112 6
        $this->writeTag('/shop');
113
114 6
        $this->write('</yml_catalog>');
115
    }
116 6
117 3
    /**
118 3
     * @return null|string
119
     */
120 6
    protected function getDate()
121
    {
122
        $date = $this->date;
123
124
        if ($date === null) {
125
            $date = Yii::$app->formatter->asDatetime(new \DateTime(), 'php:Y-m-d H:i');
126
        }
127 6
128
        return $date;
129 6
    }
130 6
131
    /**
132
     * @param string $string
133
     * @throws \Exception
134
     */
135 6
    protected function write($string)
136
    {
137 6
        $this->handle->write($string);
138 6
    }
139
140
    /**
141
     * @param string $string tag name
142
     */
143
    protected function writeTag($string)
144
    {
145 6
        $this->write('<' . $string . '>' . PHP_EOL);
146
    }
147 6
148 6
    /**
149 6
     * @param BaseModel $model model
150 6
     * @param $valuesModel
151
     * @throws Exception
152 6
     */
153 6
    protected function writeModel(BaseModel $model, $valuesModel)
154
    {
155 6
        $attributes = [];
156 6
        foreach ($model->attributes() as $attribute) {
157 6
            $methodName = 'get' . ucfirst($attribute);
158 6
            $attributeValue = $valuesModel->$methodName();
159 6
160 6
            $attributes[$attribute] = $attributeValue;
161 6
        }
162
163 6
        $model->load($attributes, '');
164
        if (method_exists($valuesModel, 'getParams')) {
165
            $model->setParams($valuesModel->getParams());
166
        }
167 6
        if (method_exists($valuesModel, 'getPictures')) {
168
            $model->setPictures($valuesModel->getPictures());
169 6
        }
170 6
171
        if (!$model->validate()) {
172
            if (is_callable($onValidationError = $this->onValidationError)) {
173
                $onValidationError($model);
174
            } else {
175 6
                throw new Exception('Model values is invalid ' . serialize($model->getErrors()));
176
            }
177 6
        } else {
178
            $string = $model->getYml();
179
180 6
            $this->write($string);
181
        }
182 6
    }
183 6
184 6
    /**
185 6
     * @param string|array $modelClass class name
186 6
     */
187 6
    protected function writeEachModel($modelClass)
188
    {
189
        $class = isset($modelClass['class']) ? $modelClass['class'] : $modelClass;
190
        $findParams = isset($modelClass['findParams']) ? $modelClass['findParams'] : [];
191
192
        $newModel = $this->getNewModel($class);
193
194 6
        /* @var \yii\db\ActiveQuery $query */
195
        $query = $class::findYml($findParams);
196 6
197
        foreach ($query->batch(100) as $models) {
198 6
            foreach ($models as $model) {
199 6
                $this->writeModel($newModel, $model);
200 6
            }
201 6
        }
202 6
    }
203 6
204 6
    /**
205
     * @param $modelClass
206
     * @return Category|Currency|SimpleOffer
207
     * @throws Exception
208 6
     */
209
    protected function getNewModel($modelClass)
210
    {
211
        $obj = new $modelClass();
212
213
        if ($obj instanceof CurrencyInterface) {
214
            $model = new Currency();
215
        } elseif ($obj instanceof CategoryInterface) {
216
            $model = new Category();
217
        } elseif ($obj instanceof SimpleOfferInterface) {
218
            $model = new SimpleOffer();
219
        } else {
220
            throw new Exception('Model ' . $modelClass. ' has unknown interface');
221
        }
222
223
        return $model;
224
    }
225
}
226