Completed
Pull Request — master (#23)
by
unknown
01:14
created

Generator::addOffer()   B

Complexity

Conditions 8
Paths 12

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.4444
c 0
b 0
f 0
cc 8
nc 12
nop 1
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\OfferCondition;
18
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferGroupAwareInterface;
19
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferInterface;
20
use Bukashk0zzz\YmlGenerator\Model\Offer\OfferParam;
21
use Bukashk0zzz\YmlGenerator\Model\ShopInfo;
22
23
/**
24
 * Class Generator
25
 */
26
class Generator
27
{
28
    /**
29
     * @var string
30
     */
31
    private $tmpFile;
32
33
    /**
34
     * @var \XMLWriter
35
     */
36
    private $writer;
37
38
    /**
39
     * @var Settings
40
     */
41
    private $settings;
42
43
    /**
44
     * Generator constructor.
45
     *
46
     * @param Settings $settings
47
     */
48
    public function __construct($settings = null)
49
    {
50
        $this->settings = $settings instanceof Settings ? $settings : new Settings();
51
        $this->tmpFile = $this->settings->getOutputFile() !== null ? \tempnam(\sys_get_temp_dir(), 'YMLGenerator') : 'php://output';
52
53
        $this->writer = new \XMLWriter();
54
        $this->writer->openURI($this->tmpFile);
55
56
        if ($this->settings->getIndentString()) {
57
            $this->writer->setIndentString($this->settings->getIndentString());
58
            $this->writer->setIndent(true);
59
        }
60
    }
61
62
    /**
63
     * @param ShopInfo $shopInfo
64
     * @param array    $currencies
65
     * @param array    $categories
66
     * @param array    $offers
67
     * @param array    $deliveries
68
     *
69
     * @return bool
70
     */
71
    public function generate(ShopInfo $shopInfo, array $currencies, array $categories, array $offers, array $deliveries = [])
72
    {
73
        try {
74
            $this->addHeader();
75
76
            $this->addShopInfo($shopInfo);
77
            $this->addCurrencies($currencies);
78
            $this->addCategories($categories);
79
80
            if (\count($deliveries) !== 0) {
81
                $this->addDeliveries($deliveries);
82
            }
83
84
            $this->addOffers($offers);
85
            $this->addFooter();
86
87
            if (null !== $this->settings->getOutputFile()) {
88
                \copy($this->tmpFile, $this->settings->getOutputFile());
89
                @\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...
90
            }
91
92
            return true;
93
        } catch (\Exception $exception) {
94
            throw new \RuntimeException(\sprintf('Problem with generating YML file: %s', $exception->getMessage()), 0, $exception);
95
        }
96
    }
97
98
    /**
99
     * Add document header
100
     */
101
    protected function addHeader()
102
    {
103
        $this->writer->startDocument('1.0', $this->settings->getEncoding());
104
        $this->writer->startDTD('yml_catalog', null, 'shops.dtd');
105
        $this->writer->endDTD();
106
        $this->writer->startElement('yml_catalog');
107
        $this->writer->writeAttribute('date', \date('Y-m-d H:i'));
108
        $this->writer->startElement('shop');
109
    }
110
111
    /**
112
     * Add document footer
113
     */
114
    protected function addFooter()
115
    {
116
        $this->writer->fullEndElement();
117
        $this->writer->fullEndElement();
118
        $this->writer->endDocument();
119
    }
120
121
    /**
122
     * Adds shop element data. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#shop)
123
     *
124
     * @param ShopInfo $shopInfo
125
     */
126
    protected function addShopInfo(ShopInfo $shopInfo)
127
    {
128
        foreach ($shopInfo->toArray() as $name => $value) {
129
            if ($value !== null) {
130
                $this->writer->writeElement($name, $value);
131
            }
132
        }
133
    }
134
135
    /**
136
     * @param Currency $currency
137
     */
138
    protected function addCurrency(Currency $currency)
139
    {
140
        $this->writer->startElement('currency');
141
        $this->writer->writeAttribute('id', $currency->getId());
142
        $this->writer->writeAttribute('rate', $currency->getRate());
143
        $this->writer->endElement();
144
    }
145
146
    /**
147
     * @param Category $category
148
     */
149 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...
150
    {
151
        $this->writer->startElement('category');
152
        $this->writer->writeAttribute('id', $category->getId());
153
154
        if ($category->getParentId() !== null) {
155
            $this->writer->writeAttribute('parentId', $category->getParentId());
156
        }
157
158
        $this->writer->text($category->getName());
159
        $this->writer->fullEndElement();
160
    }
161
162
    /**
163
     * @param Delivery $delivery
164
     */
165 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...
166
    {
167
        $this->writer->startElement('option');
168
        $this->writer->writeAttribute('cost', $delivery->getCost());
169
        $this->writer->writeAttribute('days', $delivery->getDays());
170
        if ($delivery->getOrderBefore() !== null) {
171
            $this->writer->writeAttribute('order-before', $delivery->getOrderBefore());
172
        }
173
        $this->writer->endElement();
174
    }
175
176
    /**
177
     * @param OfferInterface $offer
178
     */
179
    protected function addOffer(OfferInterface $offer)
180
    {
181
        $this->writer->startElement('offer');
182
        $this->writer->writeAttribute('id', $offer->getId());
183
        $this->writer->writeAttribute('available', $offer->isAvailable() ? 'true' : 'false');
184
185
        if ($offer->getType() !== null) {
186
            $this->writer->writeAttribute('type', $offer->getType());
187
        }
188
189
        if ($offer instanceof OfferGroupAwareInterface && $offer->getGroupId() !== null) {
190
            $this->writer->writeAttribute('group_id', $offer->getGroupId());
191
        }
192
193
        foreach ($offer->toArray() as $name => $value) {
194
            if (\is_array($value)) {
195
                foreach ($value as $itemValue) {
196
                    $this->addOfferElement($name, $itemValue);
197
                }
198
            } else {
199
                $this->addOfferElement($name, $value);
200
            }
201
        }
202
        $this->addOfferParams($offer);
203
        $this->addOfferCondition($offer);
204
205
        $this->writer->fullEndElement();
206
    }
207
208
    /**
209
     * Adds <currencies> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#currencies)
210
     *
211
     * @param array $currencies
212
     */
213
    private function addCurrencies(array $currencies)
214
    {
215
        $this->writer->startElement('currencies');
216
217
        /** @var Currency $currency */
218
        foreach ($currencies as $currency) {
219
            if ($currency instanceof Currency) {
220
                $this->addCurrency($currency);
221
            }
222
        }
223
224
        $this->writer->fullEndElement();
225
    }
226
227
    /**
228
     * Adds <categories> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#categories)
229
     *
230
     * @param array $categories
231
     */
232
    private function addCategories(array $categories)
233
    {
234
        $this->writer->startElement('categories');
235
236
        /** @var Category $category */
237
        foreach ($categories as $category) {
238
            if ($category instanceof Category) {
239
                $this->addCategory($category);
240
            }
241
        }
242
243
        $this->writer->fullEndElement();
244
    }
245
246
    /**
247
     * Adds <delivery-option> element. (See https://yandex.ru/support/partnermarket/elements/delivery-options.xml)
248
     *
249
     * @param array $deliveries
250
     */
251
    private function addDeliveries(array $deliveries)
252
    {
253
        $this->writer->startElement('delivery-options');
254
255
        /** @var Delivery $delivery */
256
        foreach ($deliveries as $delivery) {
257
            if ($delivery instanceof Delivery) {
258
                $this->addDelivery($delivery);
259
            }
260
        }
261
262
        $this->writer->fullEndElement();
263
    }
264
265
    /**
266
     * Adds <offers> element. (See https://yandex.ru/support/webmaster/goods-prices/technical-requirements.xml#offers)
267
     *
268
     * @param array $offers
269
     */
270
    private function addOffers(array $offers)
271
    {
272
        $this->writer->startElement('offers');
273
274
        /** @var OfferInterface $offer */
275
        foreach ($offers as $offer) {
276
            if ($offer instanceof OfferInterface) {
277
                $this->addOffer($offer);
278
            }
279
        }
280
281
        $this->writer->fullEndElement();
282
    }
283
284
    /**
285
     * @param OfferInterface $offer
286
     */
287
    private function addOfferParams(OfferInterface $offer)
288
    {
289
        /** @var OfferParam $param */
290
        foreach ($offer->getParams() as $param) {
291
            if ($param instanceof OfferParam) {
292
                $this->writer->startElement('param');
293
294
                $this->writer->writeAttribute('name', $param->getName());
295
                if ($param->getUnit()) {
296
                    $this->writer->writeAttribute('unit', $param->getUnit());
297
                }
298
                $this->writer->text($param->getValue());
299
300
                $this->writer->endElement();
301
            }
302
        }
303
    }
304
305
306
    /**
307
     * @param OfferInterface $offer
308
     */
309
    private function addOfferCondition(OfferInterface $offer)
310
    {
311
        $params = $offer->getCondition();
312
        if ($params instanceof OfferCondition) {
313
            $this->writer->startElement('condition');
314
            $this->writer->writeAttribute('type', $params->getType());
315
            $this->writer->writeElement('reason', $params->getReasonText());
316
            $this->writer->endElement();
317
        }
318
    }
319
320
321
    /**
322
     * @param string $name
323
     * @param mixed  $value
324
     *
325
     * @return bool
326
     */
327
    private function addOfferElement($name, $value)
328
    {
329
        if ($value === null) {
330
            return false;
331
        }
332
333
        if ($value instanceof Cdata) {
334
            $this->writer->startElement($name);
335
            $this->writer->writeCdata((string) $value);
336
            $this->writer->endElement();
337
338
            return true;
339
        }
340
341
        if (\is_bool($value)) {
342
            $value = $value ? 'true' : 'false';
343
        }
344
        $this->writer->writeElement($name, $value);
345
346
        return true;
347
    }
348
}
349