Completed
Push — master ( e9548e...c0dc7e )
by Kirill
02:34
created

YmlCatalog::write()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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