Completed
Push — master ( 4a8227...2407ef )
by Bukashk0zzz
01:29
created

Generator   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 294
Duplicated Lines 7.48 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 7
dl 22
loc 294
rs 8.3396
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
B generate() 0 26 4
A addHeader() 0 9 1
A addFooter() 0 6 1
A addShopInfo() 0 8 3
A addCurrency() 0 7 1
A addCategory() 12 12 2
A addDelivery() 10 10 2
B addOffer() 0 23 6
A addCurrencies() 0 13 3
A addCategories() 0 13 3
A addDeliveries() 0 13 3
A addOffers() 0 13 3
A addOfferParams() 0 17 4
A addOfferElement() 0 13 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Generator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Generator, and based on these observations, apply Extract Interface, too.

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