Completed
Push — master ( 6e2aaf...388511 )
by Bukashk0zzz
14s
created

Generator::generate()   B

Complexity

Conditions 4
Paths 20

Size

Total Lines 26
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 16
nc 20
nop 5
1
<?php
2
3
/*
4
 * This file is part of the Bukashk0zzzYmlGenerator
5
 *
6
 * (c) Denis Golubovskiy <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Bukashk0zzz\YmlGenerator;
13
14
use Bukashk0zzz\YmlGenerator\Model\Category;
15
use Bukashk0zzz\YmlGenerator\Model\Currency;
16
use Bukashk0zzz\YmlGenerator\Model\Delivery;
17
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferGroupAwareInterface;
18
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferInterface;
19
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferParam;
20
use Bukashk0zzz\YmlGenerator\Model\ShopInfo;
21
22
/**
23
 * Class Generator
24
 */
25
class Generator
26
{
27
    /**
28
     * @var string
29
     */
30
    private $tmpFile;
31
32
    /**
33
     * @var \XMLWriter
34
     */
35
    private $writer;
36
37
    /**
38
     * @var Settings
39
     */
40
    private $settings;
41
42
    /**
43
     * Generator constructor.
44
     *
45
     * @param Settings $settings
46
     */
47
    public function __construct($settings = null)
48
    {
49
        $this->settings = $settings instanceof Settings ? $settings : new Settings();
50
        $this->tmpFile = $this->settings->getOutputFile() !== null ? \tempnam(\sys_get_temp_dir(), 'YMLGenerator') : 'php://output';
51
52
        $this->writer = new \XMLWriter();
53
        $this->writer->openURI($this->tmpFile);
54
55
        if ($this->settings->getIndentString()) {
56
            $this->writer->setIndentString($this->settings->getIndentString());
57
            $this->writer->setIndent(true);
58
        }
59
    }
60
61
    /**
62
     * @param ShopInfo $shopInfo
63
     * @param array    $currencies
64
     * @param array    $categories
65
     * @param array    $offers
66
     * @param array    $deliveries
67
     *
68
     * @return bool
69
     */
70
    public function generate(ShopInfo $shopInfo, array $currencies, array $categories, array $offers, array $deliveries = [])
71
    {
72
        try {
73
            $this->addHeader();
74
75
            $this->addShopInfo($shopInfo);
76
            $this->addCurrencies($currencies);
77
            $this->addCategories($categories);
78
79
            if (\count($deliveries) !== 0) {
80
                $this->addDeliveries($deliveries);
81
            }
82
83
            $this->addOffers($offers);
84
            $this->addFooter();
85
86
            if (null !== $this->settings->getOutputFile()) {
87
                \copy($this->tmpFile, $this->settings->getOutputFile());
88
                @\unlink($this->tmpFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
89
            }
90
91
            return true;
92
        } catch (\Exception $exception) {
93
            throw new \RuntimeException(\sprintf('Problem with generating YML file: %s', $exception->getMessage()), 0, $exception);
94
        }
95
    }
96
97
    /**
98
     * Add document header
99
     */
100
    protected function addHeader()
101
    {
102
        $this->writer->startDocument('1.0', $this->settings->getEncoding());
103
        $this->writer->startDTD('yml_catalog', null, 'shops.dtd');
104
        $this->writer->endDTD();
105
        $this->writer->startElement('yml_catalog');
106
        $this->writer->writeAttribute('date', \date('Y-m-d H:i'));
107
        $this->writer->startElement('shop');
108
    }
109
110
    /**
111
     * Add document footer
112
     */
113
    protected function addFooter()
114
    {
115
        $this->writer->fullEndElement();
116
        $this->writer->fullEndElement();
117
        $this->writer->endDocument();
118
    }
119
120
    /**
121
     * Adds shop element data. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#shop)
122
     *
123
     * @param ShopInfo $shopInfo
124
     */
125
    protected function addShopInfo(ShopInfo $shopInfo)
126
    {
127
        foreach ($shopInfo->toArray() as $name => $value) {
128
            if ($value !== null) {
129
                $this->writer->writeElement($name, $value);
130
            }
131
        }
132
    }
133
134
    /**
135
     * @param Currency $currency
136
     */
137
    protected function addCurrency(Currency $currency)
138
    {
139
        $this->writer->startElement('currency');
140
        $this->writer->writeAttribute('id', $currency->getId());
141
        $this->writer->writeAttribute('rate', $currency->getRate());
142
        $this->writer->endElement();
143
    }
144
145
    /**
146
     * @param Category $category
147
     */
148 View Code Duplication
    protected function addCategory(Category $category)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
149
    {
150
        $this->writer->startElement('category');
151
        $this->writer->writeAttribute('id', $category->getId());
152
153
        if ($category->getParentId() !== null) {
154
            $this->writer->writeAttribute('parentId', $category->getParentId());
155
        }
156
157
        $this->writer->text($category->getName());
158
        $this->writer->fullEndElement();
159
    }
160
161
    /**
162
     * @param Delivery $delivery
163
     */
164 View Code Duplication
    protected function addDelivery(Delivery $delivery)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
165
    {
166
        $this->writer->startElement('option');
167
        $this->writer->writeAttribute('cost', $delivery->getCost());
168
        $this->writer->writeAttribute('days', $delivery->getDays());
169
        if ($delivery->getOrderBefore() !== null) {
170
            $this->writer->writeAttribute('order-before', $delivery->getOrderBefore());
171
        }
172
        $this->writer->endElement();
173
    }
174
175
    /**
176
     * @param OfferInterface $offer
177
     */
178
    protected function addOffer(OfferInterface $offer)
179
    {
180
        $this->writer->startElement('offer');
181
        $this->writer->writeAttribute('id', $offer->getId());
182
        $this->writer->writeAttribute('available', $offer->isAvailable() ? 'true' : 'false');
183
184
        if ($offer->getType() !== null) {
185
            $this->writer->writeAttribute('type', $offer->getType());
186
        }
187
188
        if ($offer instanceof OfferGroupAwareInterface && $offer->getGroupId() !== null) {
189
            $this->writer->writeAttribute('group_id', $offer->getGroupId());
190
        }
191
192
        foreach ($offer->toArray() as $name => $value) {
193
            if (\is_array($value)) {
194
                foreach ($value as $itemValue) {
195
                    $this->addOfferElement($name, $itemValue);
196
                }
197
            } else {
198
                $this->addOfferElement($name, $value);
199
            }
200
        }
201
        $this->addOfferParams($offer);
202
203
        $this->writer->fullEndElement();
204
    }
205
206
    /**
207
     * Adds <currencies> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#currencies)
208
     *
209
     * @param array $currencies
210
     */
211
    private function addCurrencies(array $currencies)
212
    {
213
        $this->writer->startElement('currencies');
214
215
        /** @var Currency $currency */
216
        foreach ($currencies as $currency) {
217
            if ($currency instanceof Currency) {
218
                $this->addCurrency($currency);
219
            }
220
        }
221
222
        $this->writer->fullEndElement();
223
    }
224
225
    /**
226
     * Adds <categories> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#categories)
227
     *
228
     * @param array $categories
229
     */
230
    private function addCategories(array $categories)
231
    {
232
        $this->writer->startElement('categories');
233
234
        /** @var Category $category */
235
        foreach ($categories as $category) {
236
            if ($category instanceof Category) {
237
                $this->addCategory($category);
238
            }
239
        }
240
241
        $this->writer->fullEndElement();
242
    }
243
244
    /**
245
     * Adds <delivery-option> element. (See https://yandex.ru/support/partnermarket/elements/delivery-options.xml)
246
     *
247
     * @param array $deliveries
248
     */
249
    private function addDeliveries(array $deliveries)
250
    {
251
        $this->writer->startElement('delivery-options');
252
253
        /** @var Delivery $delivery */
254
        foreach ($deliveries as $delivery) {
255
            if ($delivery instanceof Delivery) {
256
                $this->addDelivery($delivery);
257
            }
258
        }
259
260
        $this->writer->fullEndElement();
261
    }
262
263
    /**
264
     * Adds <offers> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#offers)
265
     *
266
     * @param array $offers
267
     */
268
    private function addOffers(array $offers)
269
    {
270
        $this->writer->startElement('offers');
271
272
        /** @var OfferInterface $offer */
273
        foreach ($offers as $offer) {
274
            if ($offer instanceof OfferInterface) {
275
                $this->addOffer($offer);
276
            }
277
        }
278
279
        $this->writer->fullEndElement();
280
    }
281
282
    /**
283
     * @param OfferInterface $offer
284
     */
285
    private function addOfferParams(OfferInterface $offer)
286
    {
287
        /** @var OfferParam $param */
288
        foreach ($offer->getParams() as $param) {
289
            if ($param instanceof OfferParam) {
290
                $this->writer->startElement('param');
291
292
                $this->writer->writeAttribute('name', $param->getName());
293
                if ($param->getUnit()) {
294
                    $this->writer->writeAttribute('unit', $param->getUnit());
295
                }
296
                $this->writer->text($param->getValue());
297
298
                $this->writer->endElement();
299
            }
300
        }
301
    }
302
303
    /**
304
     * @param string $name
305
     * @param mixed  $value
306
     *
307
     * @return bool
308
     */
309
    private function addOfferElement($name, $value)
310
    {
311
        if ($value === null) {
312
            return false;
313
        }
314
315
        if (\is_bool($value)) {
316
            $value = $value ? 'true' : 'false';
317
        }
318
        $this->writer->writeElement($name, $value);
319
320
        return true;
321
    }
322
}
323