AbstractFeedType   A
last analyzed

Complexity

Total Complexity 15

Size/Duplication

Total Lines 207
Duplicated Lines 19.81 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 93.75%

Importance

Changes 0
Metric Value
wmc 15
lcom 1
cbo 14
dl 41
loc 207
ccs 60
cts 64
cp 0.9375
rs 10
c 0
b 0
f 0

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getOriginalIdCallback() 0 6 1
A getOriginalUrlCallback() 0 6 1
A addTransformerBetween() 0 16 1
A getSourceManager() 0 4 1
getOriginalIdField() 0 1 ?
getOriginalUrlField() 0 1 ?
getModificationDateField() 0 1 ?
A setOptions() 24 24 1
A build() 0 37 2
A getModificationDateCallback() 0 18 4
A addModifierBetween() 17 17 3

How to fix   Duplicated Code   

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:

1
<?php
2
3
namespace TreeHouse\IoBundle\Import\Feed\Type;
4
5
use Symfony\Component\HttpFoundation\ParameterBag;
6
use Symfony\Component\OptionsResolver\OptionsResolver;
7
use TreeHouse\Feeder\Modifier\Data\Transformer\TransformerInterface;
8
use TreeHouse\Feeder\Modifier\Item\ModifierInterface;
9
use TreeHouse\Feeder\Modifier\Item\Transformer as FeederTransformer;
10
use TreeHouse\IoBundle\Entity\Feed;
11
use TreeHouse\IoBundle\Import\Feed\FeedBuilderInterface;
12
use TreeHouse\IoBundle\Item\Modifier\Item\Filter\BlockedSourceFilter;
13
use TreeHouse\IoBundle\Item\Modifier\Item\Filter\ModifiedItemFilter;
14
use TreeHouse\IoBundle\Item\Modifier\Item\Mapper\FeedItemBagMapper;
15
use TreeHouse\IoBundle\Item\Modifier\Item\Validator\OriginIdValidator;
16
use TreeHouse\IoBundle\Source\Manager\CachedSourceManager;
17
18
abstract class AbstractFeedType implements FeedTypeInterface
19
{
20
    /**
21
     * @var CachedSourceManager
22
     */
23
    protected $sourceManager;
24
25
    /**
26
     * @param CachedSourceManager $sourceManager
27
     */
28 4
    public function __construct(CachedSourceManager $sourceManager)
29
    {
30 4
        $this->sourceManager = $sourceManager;
31 4
    }
32
33
    /**
34
     * @inheritdoc
35
     */
36 4 View Code Duplication
    public function setOptions(OptionsResolver $resolver)
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...
37
    {
38 4
        $resolver->setRequired([
39 4
            'forced',
40
            'feed',
41
            'date_locale',
42
            'number_locale',
43
            'default_values',
44
        ]);
45
46 4
        $resolver->setAllowedValues('date_locale', ['en', 'nl']);
47 4
        $resolver->setAllowedValues('number_locale', ['en', 'nl']);
48
49 4
        $resolver->setAllowedTypes('forced', 'bool');
50 4
        $resolver->setAllowedTypes('feed', Feed::class);
51 4
        $resolver->setAllowedTypes('default_values', 'array');
52
53 4
        $resolver->setDefaults([
54 4
            'forced' => false,
55
            'date_locale' => 'en',
56
            'number_locale' => 'en',
57
            'default_values' => [],
58
        ]);
59 4
    }
60
61
    /**
62
     * @inheritdoc
63
     */
64 4
    public function build(FeedBuilderInterface $builder, array $options)
65
    {
66 4
        $sourceManager = $this->getSourceManager();
67
68
        // range 100-200: first make sure we have consistent keys and a valid origin
69 4
        $this->addModifierBetween($builder, new FeederTransformer\LowercaseKeysTransformer(), 100, 200);
70 4
        $this->addModifierBetween($builder, new FeederTransformer\UnderscoreKeysTransformer(), 100, 200);
71 4
        $this->addModifierBetween($builder, new FeederTransformer\StripKeysPunctuationTransformer(), 100, 200);
72 4
        $this->addModifierBetween($builder, new FeederTransformer\ExpandAttributesTransformer(), 100, 200);
73 4
        $this->addModifierBetween($builder, new FeederTransformer\TrimTransformer(), 100, 200);
74 4
        $this->addModifierBetween($builder, new FeederTransformer\StripCommentsTransformer(), 100, 200);
75
76
        // This transforms the regular ItemBag into our own FeedItemBag,
77
        // which adds logic for the original id/url and modification date.
78
        // We need to do this early on, since some of our filter/transformation
79
        // listeners depend on this.
80 4
        $mapper = new FeedItemBagMapper(
81 4
            $options['feed'],
82 4
            $this->getOriginalIdCallback(),
83 4
            $this->getOriginalUrlCallback(),
84 4
            $this->getModificationDateCallback()
85
        );
86 4
        $this->addModifierBetween($builder, $mapper, 200, 250);
87
88
        // range 300-400: perform validation and checks for skipping early on
89
90
        // validate origin id
91 4
        $this->addModifierBetween($builder, new OriginIdValidator(), 300, 400);
92
93
        // skip blocked sources
94 4
        $this->addModifierBetween($builder, new BlockedSourceFilter($sourceManager), 300, 400);
95
96
        // check for modification dates, but only when not forced
97 4
        if ($options['forced'] === false) {
98 4
            $this->addModifierBetween($builder, new ModifiedItemFilter($sourceManager), 300, 400);
99
        }
100 4
    }
101
102
    /**
103
     * @inheritdoc
104
     */
105 4
    public function getOriginalIdCallback()
106
    {
107
        return function (ParameterBag $item) {
108 4
            return $item->get($this->getOriginalIdField(), null, true);
109 4
        };
110
    }
111
112
    /**
113
     * @inheritdoc
114
     */
115 4
    public function getOriginalUrlCallback()
116
    {
117
        return function (ParameterBag $item) {
118 4
            return $item->get($this->getOriginalUrlField(), null, true);
119 4
        };
120
    }
121
122
    /**
123
     * @inheritdoc
124
     */
125
    public function getModificationDateCallback()
126
    {
127 4
        return function (ParameterBag $item) {
128 4
            if ($date = $item->get($this->getModificationDateField(), null, true)) {
129
                try {
130 4
                    $datetime = new \DateTime($date);
131 4
                    if ($datetime->format('H:i:s') === '00:00:00') {
132
                        $datetime->setTime(23, 59, 59);
133
                    }
134
135 4
                    return $datetime;
136
                } catch (\Exception $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
137
                }
138
            }
139
140
            return null;
141 4
        };
142
    }
143
144
    /**
145
     * Adds the given modifier between the start and end index, if there is a vacant position.
146
     *
147
     * @param FeedBuilderInterface $builder
148
     * @param ModifierInterface    $modifier
149
     * @param int                  $startIndex
150
     * @param int                  $endIndex
151
     * @param bool                 $continue
152
     *
153
     * @throws \OutOfBoundsException
154
     */
155 4 View Code Duplication
    protected function addModifierBetween(
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...
156
        FeedBuilderInterface $builder,
157
        ModifierInterface $modifier,
158
        $startIndex,
159
        $endIndex,
160
        $continue = null
161
    ) {
162 4
        for ($position = $startIndex; $position <= $endIndex; ++$position) {
163 4
            if (!$builder->hasModifierAt($position)) {
164 4
                $builder->addModifier($modifier, $position, $continue);
165
166 4
                return;
167
            }
168
        }
169
170
        throw new \OutOfBoundsException(sprintf('No position left between %d and %d', $startIndex, $endIndex));
171
    }
172
173
    /**
174
     * Adds the given transformer between the start and end index, if there is a vacant position.
175
     *
176
     * @param FeedBuilderInterface $builder
177
     * @param TransformerInterface $transformer
178
     * @param string               $field
179
     * @param int                  $startIndex
180
     * @param int                  $endIndex
181
     * @param bool                 $continue
182
     *
183
     * @throws \OutOfBoundsException
184
     */
185 4
    protected function addTransformerBetween(
186
        FeedBuilderInterface $builder,
187
        TransformerInterface $transformer,
188
        $field,
189
        $startIndex,
190
        $endIndex,
191
        $continue = null
192
    ) {
193 4
        $this->addModifierBetween(
194 4
            $builder,
195 4
            new FeederTransformer\DataTransformer($transformer, $field),
196 4
            $startIndex,
197 4
            $endIndex,
198 4
            $continue
199
        );
200 4
    }
201
202
    /**
203
     * @return CachedSourceManager
204
     */
205 4
    protected function getSourceManager()
206
    {
207 4
        return $this->sourceManager;
208
    }
209
210
    /**
211
     * @return string
212
     */
213
    abstract protected function getOriginalIdField();
214
215
    /**
216
     * @return string
217
     */
218
    abstract protected function getOriginalUrlField();
219
220
    /**
221
     * @return string
222
     */
223
    abstract protected function getModificationDateField();
224
}
225