Failed Conditions
Push — dev/plugin-misc ( f22d99...066a4d )
by Kiyotaka
10:54 queued 03:43
created

CustomerRepository   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 333
Duplicated Lines 21.62 %

Coupling/Cohesion

Components 2
Dependencies 8

Importance

Changes 0
Metric Value
dl 72
loc 333
rs 6.96
c 0
b 0
f 0
wmc 53
lcom 2
cbo 8

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 16 1
A newCustomer() 0 11 1
F getQueryBuilderBySearchData() 54 151 41
A getUniqueSecretKey() 9 9 2
A getUniqueResetKey() 9 9 2
A getProvisionalCustomerBySecretKey() 0 7 1
A getRegularCustomerByEmail() 0 7 1
A getRegularCustomerByResetKey() 0 18 2
A getResetPassword() 0 4 1
A getNonWithdrawingCustomers() 0 9 1

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 CustomerRepository 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 CustomerRepository, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) LOCKON CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.lockon.co.jp/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Eccube\Repository;
15
16
use Doctrine\ORM\EntityManagerInterface;
17
use Eccube\Common\EccubeConfig;
18
use Eccube\Doctrine\Query\Queries;
19
use Eccube\Entity\Customer;
20
use Eccube\Entity\Master\CustomerStatus;
21
use Eccube\Util\StringUtil;
22
use Symfony\Bridge\Doctrine\RegistryInterface;
23
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
24
25
/**
26
 * CustomerRepository
27
 *
28
 * This class was generated by the Doctrine ORM. Add your own custom
29
 * repository methods below.
30
 */
31
class CustomerRepository extends AbstractRepository
32
{
33
    /**
34
     * @var Queries
35
     */
36
    protected $queries;
37
38
    /**
39
     * @var EntityManagerInterface
40
     */
41
    protected $entityManager;
42
43
    /**
44
     * @var OrderRepository
45
     */
46
    protected $orderRepository;
47
48
    /**
49
     * @var EccubeConfig
50
     */
51
    protected $eccubeConfig;
52
53
    /**
54
     * @var EncoderFactoryInterface
55
     */
56
    protected $encoderFactory;
57
58
    /**
59
     * CustomerRepository constructor.
60
     *
61
     * @param RegistryInterface $registry
62
     * @param Queries $queries
63
     * @param EntityManagerInterface $entityManager
64
     * @param OrderRepository $orderRepository
65
     * @param EncoderFactoryInterface $encoderFactory
66
     * @param EccubeConfig $eccubeConfig
67
     */
68
    public function __construct(
69
        RegistryInterface $registry,
70
        Queries $queries,
71
        EntityManagerInterface $entityManager,
72
        OrderRepository $orderRepository,
73
        EncoderFactoryInterface $encoderFactory,
74
        EccubeConfig $eccubeConfig
75
    ) {
76
        parent::__construct($registry, Customer::class);
77
78
        $this->queries = $queries;
79
        $this->entityManager = $entityManager;
80
        $this->orderRepository = $orderRepository;
81
        $this->encoderFactory = $encoderFactory;
82
        $this->eccubeConfig = $eccubeConfig;
83
    }
84
85
    public function newCustomer()
86
    {
87
        $CustomerStatus = $this->getEntityManager()
88
            ->find(CustomerStatus::class, CustomerStatus::PROVISIONAL);
89
90
        $Customer = new \Eccube\Entity\Customer();
91
        $Customer
92
            ->setStatus($CustomerStatus);
0 ignored issues
show
Bug introduced by
It seems like $CustomerStatus defined by $this->getEntityManager(...merStatus::PROVISIONAL) on line 87 can also be of type object; however, Eccube\Entity\Customer::setStatus() does only seem to accept null|object<Eccube\Entity\Master\CustomerStatus>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
93
94
        return $Customer;
95
    }
96
97
    public function getQueryBuilderBySearchData($searchData)
98
    {
99
        $qb = $this->createQueryBuilder('c')
100
            ->select('c');
101
102
        if (isset($searchData['multi']) && StringUtil::isNotBlank($searchData['multi'])) {
103
            //スペース除去
104
            $clean_key_multi = preg_replace('/\s+|[ ]+/u', '', $searchData['multi']);
105
            $id = preg_match('/^\d{0,10}$/', $clean_key_multi) ? $clean_key_multi : null;
106
            $qb
107
                ->andWhere('c.id = :customer_id OR CONCAT(c.name01, c.name02) LIKE :name OR CONCAT(c.kana01, c.kana02) LIKE :kana OR c.email LIKE :email')
108
                ->setParameter('customer_id', $id)
109
                ->setParameter('name', '%'.$clean_key_multi.'%')
110
                ->setParameter('kana', '%'.$clean_key_multi.'%')
111
                ->setParameter('email', '%'.$clean_key_multi.'%');
112
        }
113
114
        // Pref
115
        if (!empty($searchData['pref']) && $searchData['pref']) {
116
            $qb
117
                ->andWhere('c.Pref = :pref')
118
                ->setParameter('pref', $searchData['pref']->getId());
119
        }
120
121
        // sex
122
        if (!empty($searchData['sex']) && count($searchData['sex']) > 0) {
123
            $sexs = [];
124
            foreach ($searchData['sex'] as $sex) {
125
                $sexs[] = $sex->getId();
126
            }
127
128
            $qb
129
                ->andWhere($qb->expr()->in('c.Sex', ':sexs'))
130
                ->setParameter('sexs', $sexs);
131
        }
132
133
        if (!empty($searchData['birth_month']) && $searchData['birth_month']) {
134
            $qb
135
                ->andWhere('EXTRACT(MONTH FROM c.birth) = :birth_month')
136
                ->setParameter('birth_month', $searchData['birth_month']);
137
        }
138
139
        // birth
140
        if (!empty($searchData['birth_start']) && $searchData['birth_start']) {
141
            $qb
142
                ->andWhere('c.birth >= :birth_start')
143
                ->setParameter('birth_start', $searchData['birth_start']);
144
        }
145 View Code Duplication
        if (!empty($searchData['birth_end']) && $searchData['birth_end']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
146
            $date = clone $searchData['birth_end'];
147
            $date->modify('+1 days');
148
            $qb
149
                ->andWhere('c.birth < :birth_end')
150
                ->setParameter('birth_end', $date);
151
        }
152
153
        // tel
154 View Code Duplication
        if (isset($searchData['phone_number']) && StringUtil::isNotBlank($searchData['phone_number'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
155
            $tel = preg_replace('/[^0-9]/ ', '', $searchData['phone_number']);
156
            $qb
157
                ->andWhere('c.phone_number LIKE :phone_number')
158
                ->setParameter('phone_number', '%'.$tel.'%');
159
        }
160
161
        // buy_total
162 View Code Duplication
        if (isset($searchData['buy_total_start']) && StringUtil::isNotBlank($searchData['buy_total_start'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
163
            $qb
164
                ->andWhere('c.buy_total >= :buy_total_start')
165
                ->setParameter('buy_total_start', $searchData['buy_total_start']);
166
        }
167 View Code Duplication
        if (isset($searchData['buy_total_end']) && StringUtil::isNotBlank($searchData['buy_total_end'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
168
            $qb
169
                ->andWhere('c.buy_total <= :buy_total_end')
170
                ->setParameter('buy_total_end', $searchData['buy_total_end']);
171
        }
172
173
        // buy_times
174 View Code Duplication
        if (isset($searchData['buy_times_start']) && StringUtil::isNotBlank($searchData['buy_times_start'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
175
            $qb
176
                ->andWhere('c.buy_times >= :buy_times_start')
177
                ->setParameter('buy_times_start', $searchData['buy_times_start']);
178
        }
179 View Code Duplication
        if (isset($searchData['buy_times_end']) && StringUtil::isNotBlank($searchData['buy_times_end'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
180
            $qb
181
                ->andWhere('c.buy_times <= :buy_times_end')
182
                ->setParameter('buy_times_end', $searchData['buy_times_end']);
183
        }
184
185
        // create_date
186
        if (!empty($searchData['create_date_start']) && $searchData['create_date_start']) {
187
            $qb
188
                ->andWhere('c.create_date >= :create_date_start')
189
                ->setParameter('create_date_start', $searchData['create_date_start']);
190
        }
191 View Code Duplication
        if (!empty($searchData['create_date_end']) && $searchData['create_date_end']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
192
            $date = clone $searchData['create_date_end'];
193
            $date->modify('+1 days');
194
            $qb
195
                ->andWhere('c.create_date < :create_date_end')
196
                ->setParameter('create_date_end', $date);
197
        }
198
199
        // update_date
200
        if (!empty($searchData['update_date_start']) && $searchData['update_date_start']) {
201
            $qb
202
                ->andWhere('c.update_date >= :update_date_start')
203
                ->setParameter('update_date_start', $searchData['update_date_start']);
204
        }
205 View Code Duplication
        if (!empty($searchData['update_date_end']) && $searchData['update_date_end']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
206
            $date = clone $searchData['update_date_end'];
207
            $date->modify('+1 days');
208
            $qb
209
                ->andWhere('c.update_date < :update_date_end')
210
                ->setParameter('update_date_end', $date);
211
        }
212
213
        // last_buy
214
        if (!empty($searchData['last_buy_start']) && $searchData['last_buy_start']) {
215
            $qb
216
                ->andWhere('c.last_buy_date >= :last_buy_start')
217
                ->setParameter('last_buy_start', $searchData['last_buy_start']);
218
        }
219 View Code Duplication
        if (!empty($searchData['last_buy_end']) && $searchData['last_buy_end']) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
220
            $date = clone $searchData['last_buy_end'];
221
            $date->modify('+1 days');
222
            $qb
223
                ->andWhere('c.last_buy_date < :last_buy_end')
224
                ->setParameter('last_buy_end', $date);
225
        }
226
227
        // status
228
        if (!empty($searchData['customer_status']) && count($searchData['customer_status']) > 0) {
229
            $qb
230
                ->andWhere($qb->expr()->in('c.Status', ':statuses'))
231
                ->setParameter('statuses', $searchData['customer_status']);
232
        }
233
234
        // buy_product_name
235
        if (isset($searchData['buy_product_name']) && StringUtil::isNotBlank($searchData['buy_product_name'])) {
236
            $qb
237
                ->leftJoin('c.Orders', 'o')
238
                ->leftJoin('o.OrderItems', 'oi')
239
                ->andWhere('oi.product_name LIKE :buy_product_name')
240
                ->setParameter('buy_product_name', '%'.$searchData['buy_product_name'].'%');
241
        }
242
243
        // Order By
244
        $qb->addOrderBy('c.update_date', 'DESC');
245
246
        return $this->queries->customize(QueryKey::CUSTOMER_SEARCH, $qb, $searchData);
247
    }
248
249
    /**
250
     * ユニークなシークレットキーを返す.
251
     *
252
     * @return string
253
     */
254 View Code Duplication
    public function getUniqueSecretKey()
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...
255
    {
256
        do {
257
            $key = StringUtil::random(32);
258
            $Customer = $this->findOneBy(['secret_key' => $key]);
259
        } while ($Customer);
260
261
        return $key;
262
    }
263
264
    /**
265
     * ユニークなパスワードリセットキーを返す
266
     *
267
     * @return string
268
     */
269 View Code Duplication
    public function getUniqueResetKey()
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...
270
    {
271
        do {
272
            $key = StringUtil::random(32);
273
            $Customer = $this->findOneBy(['reset_key' => $key]);
274
        } while ($Customer);
275
276
        return $key;
277
    }
278
279
    /**
280
     * 仮会員をシークレットキーで検索する.
281
     *
282
     * @param $secretKey
283
     *
284
     * @return null|Customer 見つからない場合はnullを返す.
285
     */
286
    public function getProvisionalCustomerBySecretKey($secretKey)
287
    {
288
        return $this->findOneBy([
289
            'secret_key' => $secretKey,
290
            'Status' => CustomerStatus::PROVISIONAL,
291
        ]);
292
    }
293
294
    /**
295
     * 本会員をemailで検索する.
296
     *
297
     * @param $email
298
     *
299
     * @return null|Customer 見つからない場合はnullを返す.
300
     */
301
    public function getRegularCustomerByEmail($email)
302
    {
303
        return $this->findOneBy([
304
            'email' => $email,
305
            'Status' => CustomerStatus::REGULAR,
306
        ]);
307
    }
308
309
    /**
310
     * 本会員をリセットキー、またはリセットキーとメールアドレスで検索する.
311
     *
312
     * @param $resetKey
313
     * @param $email
314
     *
315
     * @return null|Customer 見つからない場合はnullを返す.
316
     */
317
    public function getRegularCustomerByResetKey($resetKey, $email = null)
318
    {
319
        $qb = $this->createQueryBuilder('c')
320
            ->where('c.reset_key = :reset_key AND c.Status = :status AND c.reset_expire >= :reset_expire')
321
            ->setParameter('reset_key', $resetKey)
322
            ->setParameter('status', CustomerStatus::REGULAR)
323
            ->setParameter('reset_expire', new \DateTime());
324
325
        if ($email) {
326
            $qb
327
                ->andWhere('c.email = :email')
328
                ->setParameter('email', $email);
329
        }
330
331
        return $qb->setMaxResults(1)
332
            ->getQuery()
333
            ->getOneOrNullResult();
334
    }
335
336
    /**
337
     * リセット用パスワードを生成する.
338
     *
339
     * @return string
340
     */
341
    public function getResetPassword()
342
    {
343
        return StringUtil::random(8);
344
    }
345
346
    /**
347
     * 仮会員, 本会員の会員を返す.
348
     * Eccube\Entity\CustomerのUniqueEntityバリデーションで使用しています.
349
     *
350
     * @param array $criteria
351
     *
352
     * @return Customer[]
353
     */
354
    public function getNonWithdrawingCustomers(array $criteria = [])
355
    {
356
        $criteria['Status'] = [
357
            CustomerStatus::PROVISIONAL,
358
            CustomerStatus::REGULAR,
359
        ];
360
361
        return $this->findBy($criteria);
362
    }
363
}
364