Completed
Pull Request — master (#6)
by
unknown
04:50
created

YmlCatalog::writeModel()   B

Complexity

Conditions 5
Paths 16

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

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