ProductExportManager   A
last analyzed

Complexity

Total Complexity 21

Size/Duplication

Total Lines 197
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 0 Features 2
Metric Value
wmc 21
c 2
b 0
f 2
lcom 1
cbo 5
dl 0
loc 197
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 12 1
A updateProductExports() 0 6 2
B updateProductExport() 0 51 5
A filterProducts() 0 14 3
A filterProduct() 0 21 4
B filterProductValues() 0 21 6
1
<?php
2
3
namespace Actualys\Bundle\DrupalCommerceConnectorBundle\Manager;
4
5
use PDO;
6
use Doctrine\Common\Persistence\ObjectManager;
7
use Doctrine\ORM\EntityManager;
8
use Pim\Bundle\CatalogBundle\Model\AbstractProduct;
9
use Akeneo\Bundle\BatchBundle\Entity\JobInstance;
10
use Pim\Bundle\CatalogBundle\Repository\ReferableEntityRepositoryInterface;
11
use PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct;
12
13
14
class ProductExportManager
15
{
16
    /**
17
     * @var boolean
18
     */
19
    protected $productValueDelta;
20
21
    /**
22
     * @var EntityManager
23
     */
24
    protected $entityManager;
25
26
    /**
27
     * @var string
28
     */
29
    protected $productExportClass;
30
31
    /**
32
     * @var EntityRepository
33
     */
34
    protected $productExportRepository;
35
36
37
    /**
38
     * @var EntityRepository
39
     */
40
    protected $productRepository;
41
42
    /**
43
     * Constructor
44
     *
45
     * @param EntityManager $entityManager      Entity manager for other entitites
46
     * @param string        $productExportClass ProductExport class
47
     * @param string        $productClass       Product class
48
     * @param boolean       $productValueDelta  Should we do a delta on product values
49
     */
50
    public function __construct(
51
      EntityManager $entityManager,
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $entityManager. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
52
      $productExportClass,
53
      $productClass,
54
      $productValueDelta = false
55
    ) {
56
        $this->entityManager           = $entityManager;
57
        $this->productExportClass      = $productExportClass;
58
        $this->productExportRepository = $this->entityManager->getRepository($this->productExportClass);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->entityManager->ge...is->productExportClass) of type object<Doctrine\ORM\EntityRepository> is incompatible with the declared type object<Actualys\Bundle\D...nager\EntityRepository> of property $productExportRepository.

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...
59
        $this->productRepository       = $this->entityManager->getRepository($productClass);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->entityManager->ge...pository($productClass) of type object<Doctrine\ORM\EntityRepository> is incompatible with the declared type object<Actualys\Bundle\D...nager\EntityRepository> of property $productRepository.

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...
60
        $this->productValueDelta       = $productValueDelta;
61
    }
62
    /**
63
     * Update product export dates for the given products
64
     * @param array       $products
65
     * @param JobInstance $jobInstance
66
     */
67
    public function updateProductExports($products, JobInstance $jobInstance)
68
    {
69
        foreach ($products as $product) {
70
            $this->updateProductExport($product->getIdentifier(), $jobInstance);
71
        }
72
    }
73
74
    /**
75
     * Update product export date for the given product
76
     * @param string      $identifier
77
     * @param JobInstance $jobInstance
78
     */
79
    public function updateProductExport($identifier, JobInstance $jobInstance)
80
    {
81
        $now = new \DateTime('now', new \DateTimeZone('UTC'));
82
        $product = $this->productRepository->findByReference((string) $identifier);
83
        if (class_exists('\PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct')) {
84
            if ($product instanceof \PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct ) {
0 ignored issues
show
Bug introduced by
The class PimEnterprise\Bundle\Wor...\Model\PublishedProduct does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
85
                /**@var \PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct  $product **/
86
                $productId = $product->getOriginalProduct()->getId();
0 ignored issues
show
Unused Code introduced by
$productId is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
87
                $product = $product->getOriginalProduct();
88
            }
89
        }
90
91
        if (null != $product) {
92
            $productExport = $this->productExportRepository->findOneBy(array(
93
                'product'     => $product,
94
                'jobInstance' => $jobInstance
95
              ));
96
97
            $conn = $this->entityManager->getConnection();
98
99
            $jobInstance->getId();
0 ignored issues
show
Unused Code introduced by
The call to the method Akeneo\Bundle\BatchBundl...ty\JobInstance::getId() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
100
            $product->getId();
101
102
103
            if (null === $productExport) {
104
                $sql = '
105
                    INSERT INTO pim_delta_product_export
106
                    (product_id, job_instance_id, date)
107
                    VALUES (:product_id, :job_instance_id, :date)
108
                ';
109
            } else {
110
                $sql = '
111
                    UPDATE pim_delta_product_export
112
                    SET date = :date
113
                    WHERE product_id = :product_id AND job_instance_id = :job_instance_id
114
                ';
115
            }
116
117
            $q = $conn->prepare($sql);
118
            $date = $now->format('Y-m-d H:i:s');
119
            $productId = $product->getId();
120
            $jobInstanceId = $jobInstance->getId();
121
122
123
124
            $q->bindParam(':date', $date, PDO::PARAM_STR);
125
            $q->bindParam(':product_id', $productId, PDO::PARAM_INT);
126
            $q->bindParam(':job_instance_id', $jobInstanceId, PDO::PARAM_INT);
127
            $q->execute();
128
        }
129
    }
130
131
    /**
132
     * Filter products to export
133
     * @param array       $products
134
     * @param JobInstance $jobInstance
135
     *
136
     * @return AbstractProduct
137
     */
138
    public function filterProducts($products, JobInstance $jobInstance)
139
    {
140
        $productsToExport = array();
141
142
        foreach ($products as $product) {
143
            $product = $this->filterProduct($product, $jobInstance);
144
145
            if (null !== $product) {
146
                $productsToExport[] = $product;
147
            }
148
        }
149
150
        return $productsToExport;
151
    }
152
153
    /**
154
     * Filter a product (return null if the product got exported after his last edit)
155
     * @param AbstractProduct $product
156
     * @param JobInstance     $jobInstance
157
     *
158
     * @return AbstractProduct|null
159
     */
160
    public function filterProduct(AbstractProduct $product, JobInstance $jobInstance)
161
    {
162
        if ($product instanceof \PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct ) {
0 ignored issues
show
Bug introduced by
The class PimEnterprise\Bundle\Wor...\Model\PublishedProduct does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
163
            /**@var \PimEnterprise\Bundle\WorkflowBundle\Model\PublishedProduct  $product **/
164
            $productExport = $this->productExportRepository->findProductExportAfterEdit(
165
              $product->getOriginalProduct(),
166
              $jobInstance,
167
              $product->getUpdated()
168
            );
169
170
            if (0 === count($productExport)) {
171
                if ($this->productValueDelta) {
172
                    $product = $this->filterProductValues($product);
173
                }
174
            } else {
175
                $product = null;
176
            }
177
        }
178
179
        return $product;
180
    }
181
182
    /**
183
     * Filter on product values
184
     *
185
     * @param AbstractProduct $product
186
     *
187
     * @return AbstractProduct
188
     */
189
    public function filterProductValues(AbstractProduct $product)
190
    {
191
        $this->entityManager->detach($product);
192
        $productValues  = $product->getValues();
193
        $identifierType = $product->getIdentifier()->getAttribute()->getAttributeType();
194
195
        foreach ($productValues as $productValue) {
196
197
            if ($identifierType != $productValue->getAttribute()->getAttributeType() && (
198
                null == $productValue->getUpdated() || (
199
                  null != $productValue->getUpdated() &&
200
                  $product->getUpdated()->getTimestamp() - $productValue->getUpdated()->getTimestamp() > 60
201
                )
202
              )
203
            ) {
204
                $product->removeValue($productValue);
205
            }
206
        }
207
208
        return $product;
209
    }
210
}
211