Completed
Push — master ( 0c5536...d4f264 )
by
unknown
15s queued 10s
created

EntityExtractorTrait::processObject()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 6.105

Importance

Changes 0
Metric Value
dl 0
loc 26
c 0
b 0
f 0
ccs 12
cts 14
cp 0.8571
rs 8.8817
cc 6
nc 5
nop 2
crap 6.105
1
<?php
2
3
namespace Smart\EtlBundle\Extractor;
4
5
use Smart\EtlBundle\Exception\Extractor\EntityAlreadyRegisteredException;
6
use Smart\EtlBundle\Exception\Extractor\EntityIdentifiedNotFoundException;
7
use Smart\EtlBundle\Exception\Extractor\EntityIdentifierAlreadyProcessedException;
8
use Smart\EtlBundle\Exception\Extractor\EntityTypeNotHandledException;
9
use Symfony\Component\PropertyAccess\PropertyAccess;
10
11
/**
12
 * Nicolas Bastien <[email protected]>
13
 */
14
trait EntityExtractorTrait
15
{
16
    /**
17
     * List of entities to extract
18
     * [
19
     *      'entity_code' => 'Model Classname'
20
     * ]
21
     * @var array
22
     */
23
    protected $entitiesToProcess = [];
24
25
    /**
26
     * @var array
27
     */
28
    protected $entities = [];
29
30
    /**
31
     * @var PropertyAccessor
32
     */
33
    protected $accessor;
34
35
    /**
36
     * @param string $entityType
37
     * @param string$entityClass
38
     * @param function $identifierCallback
39
     * @return $this
40
     * @throws \Exception
41
     */
42 6
    public function addEntityToProcess($entityType, $entityClass, $identifierCallback)
43
    {
44 6
        if (isset($this->entitiesToProcess[$entityType])) {
45 1
            throw new EntityAlreadyRegisteredException($entityType);
46
        }
47
48 6
        $this->entitiesToProcess[$entityType] = [
49 6
            'type' => $entityType,
50 6
            'class' => $entityClass,
51 6
            'callback' => $identifierCallback
52
        ];
53
54 6
        return $this;
55
    }
56
57
    /**
58
     * @inheritDoc
59
     */
60 5
    public function extract()
61
    {
62
        try {
63 5
            $this->init();
64 5
            $this->check();
65
66 5
            $files = $this->getFiles($this->getFileExtension());
0 ignored issues
show
Bug introduced by
It seems like getFileExtension() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
Bug introduced by
It seems like getFiles() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
67 5
            foreach ($this->entitiesToProcess as $entityType => $data) {
68 5
                if (!isset($files[$entityType])) {
69
                    continue;
70
                }
71 5
                $this->processFile($entityType);
72
            }
73
74 3
            return $this->entities;
75 2
        } catch (\Exception $e) {
76 2
            throw $e;
77
        }
78
    }
79
80 5
    protected function check()
81
    {
82 5
        parent::check();
83
84 5
        if (count($this->entitiesToProcess) === 0) {
85
            throw new \BadMethodCallException('Nothing to process');
86
        }
87 5
    }
88
89 5
    protected function init()
90
    {
91 5
        $this->accessor = PropertyAccess::createPropertyAccessor();
0 ignored issues
show
Documentation Bug introduced by
It seems like \Symfony\Component\Prope...reatePropertyAccessor() of type object<Symfony\Component...ccess\PropertyAccessor> is incompatible with the declared type object<Smart\EtlBundle\E...actor\PropertyAccessor> of property $accessor.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
92 5
    }
93
94
    /**
95
     * @param string $entityType
96
     * @param array $data
97
     * @return mixed
98
     * @throws \Exception
99
     */
100 5
    protected function processObject($entityType, array $data)
101
    {
102 5
        if (!isset($this->entitiesToProcess[$entityType])) {
103
            throw new EntityTypeNotHandledException($entityType);
104
        }
105
106 5
        $data = $this->transformData($data);
0 ignored issues
show
Bug introduced by
It seems like transformData() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
107 5
        if ($data === null) {
108
            return null;
109
        }
110
111 5
        $objectClass = $this->entitiesToProcess[$entityType]['class'];
112 5
        $object = new $objectClass();
113
114 5
        foreach ($data as $key => $value) {
115 5
            $valueToSet = $value;
116 5
            if (is_string($value) && strpos($value, '@') === 0) {
117
                //handle relations
118 3
                $valueToSet = $this->getEntity($value);
119
            }
120
121 5
            $this->accessor->setValue($object, $key, $valueToSet);
122
        }
123
124 4
        return $object;
125
    }
126
127
    /**
128
     * @param string $identifier
129
     * @return mixed
130
     * @throws \Exception
131
     */
132 3
    protected function getEntity($identifier)
133
    {
134 3
        if (strpos($identifier, '@') === 0) {
135 3
            $identifier = substr($identifier, 1);
136
        }
137 3
        if (!isset($this->entities[$identifier])) {
138 1
            throw new EntityIdentifiedNotFoundException($identifier);
139
        }
140
141 2
        return $this->entities[$identifier];
142
    }
143
144
    /**
145
     * @param  string $filename
146
     * @throws \Exception
147
     */
148 5
    protected function processFile($filename)
149
    {
150 5
        $filepath = sprintf('%s/%s.' . $this->getFileExtension(), $this->folderToExtract, $filename);
0 ignored issues
show
Bug introduced by
The property folderToExtract does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
Bug introduced by
It seems like getFileExtension() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
151
152 5
        $data = $this->extractFileContent($filepath);
0 ignored issues
show
Bug introduced by
The method extractFileContent() does not exist on Smart\EtlBundle\Extractor\EntityExtractorTrait. Did you maybe mean extract()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
153 5
        foreach ($data as $values) {
154 5
            if ($values === null) {
155
                continue;
156
            }
157 5
            $object = $this->processObject($filename, $values);
158 4
            if ($object !== null) {
159 4
                $entityIdentifier = $this->entitiesToProcess[$filename]['callback']($object);
160 4
                if (isset($this->entities[$entityIdentifier])) {
161 1
                    throw new EntityIdentifierAlreadyProcessedException($entityIdentifier);
162
                }
163 4
                $this->entities[$entityIdentifier] = $object;
164
            }
165
        }
166 3
    }
167
}
168