Failed Conditions
Pull Request — experimental/sf (#29)
by Kentaro
50:12 queued 39:05
created

CsvExportService::getEntityManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
ccs 0
cts 2
cp 0
crap 2
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\Service;
15
16
use Doctrine\Common\Util\ClassUtils;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Doctrine\ORM\QueryBuilder;
19
use Eccube\Common\EccubeConfig;
20
use Eccube\Entity\Csv;
21
use Eccube\Entity\Master\CsvType;
22
use Eccube\Form\Type\Admin\SearchOrderType;
23
use Eccube\Form\Type\Admin\SearchProductType;
24
use Eccube\Repository\CsvRepository;
25
use Eccube\Repository\CustomerRepository;
26
use Eccube\Repository\Master\CsvTypeRepository;
27
use Eccube\Repository\OrderRepository;
28
use Eccube\Repository\ProductRepository;
29
use Eccube\Repository\ShippingRepository;
30
use Eccube\Util\EntityUtil;
31
use Eccube\Util\FormUtil;
32
use Symfony\Component\Form\FormFactoryInterface;
33
use Symfony\Component\HttpFoundation\Request;
34
35
class CsvExportService
36
{
37
    /**
38
     * @var resource
39
     */
40
    protected $fp;
41
42
    /**
43
     * @var boolean
44
     */
45
    protected $closed = false;
46
47
    /**
48
     * @var \Closure
49
     */
50
    protected $convertEncodingCallBack;
51
52
    /**
53
     * @var EntityManagerInterface
54
     */
55
    protected $entityManager;
56
57
    /**
58
     * @var QueryBuilder;
59
     */
60
    protected $qb;
61
62
    /**
63
     * @var EccubeConfig
64
     */
65
    protected $eccubeConfig;
66
67
    /**
68
     * @var CsvType
69
     */
70
    protected $CsvType;
71
72
    /**
73
     * @var Csv[]
74
     */
75
    protected $Csvs;
76
77
    /**
78
     * @var CsvRepository
79
     */
80
    protected $csvRepository;
81
82
    /**
83
     * @var CsvTypeRepository
84
     */
85
    protected $csvTypeRepository;
86
87
    /**
88
     * @var OrderRepository
89
     */
90
    protected $orderRepository;
91
92
    /**
93
     * @var ShippingRepository
94
     */
95
    protected $shippingRepository;
96
97
    /**
98
     * @var CustomerRepository
99
     */
100
    protected $customerRepository;
101
102
    /**
103
     * @var ProductRepository
104
     */
105
    protected $productRepository;
106
107
    /**
108
     * @var FormFactoryInterface
109
     */
110
    protected $formFactory;
111
112
    /**
113
     * CsvExportService constructor.
114
     *
115
     * @param EntityManagerInterface $entityManager
116
     * @param CsvRepository $csvRepository
117
     * @param CsvTypeRepository $csvTypeRepository
118
     * @param OrderRepository $orderRepository
119
     * @param CustomerRepository $customerRepository
120
     * @param EccubeConfig $eccubeConfig
121
     */
122 76
    public function __construct(
123
        EntityManagerInterface $entityManager,
124
        CsvRepository $csvRepository,
125
        CsvTypeRepository $csvTypeRepository,
126
        OrderRepository $orderRepository,
127
        ShippingRepository $shippingRepository,
128
        CustomerRepository $customerRepository,
129
        ProductRepository $productRepository,
130
        EccubeConfig $eccubeConfig,
131
        FormFactoryInterface $formFactory
132
    ) {
133 76
        $this->entityManager = $entityManager;
134 76
        $this->csvRepository = $csvRepository;
135 76
        $this->csvTypeRepository = $csvTypeRepository;
136 76
        $this->orderRepository = $orderRepository;
137 76
        $this->shippingRepository = $shippingRepository;
138 76
        $this->customerRepository = $customerRepository;
139 76
        $this->eccubeConfig = $eccubeConfig;
140 76
        $this->productRepository = $productRepository;
141 76
        $this->formFactory = $formFactory;
142
    }
143
144
    /**
145
     * @param $config
146
     */
147
    public function setConfig($config)
148
    {
149
        $this->eccubeConfig = $config;
150
    }
151
152
    /**
153
     * @param CsvRepository $csvRepository
154
     */
155
    public function setCsvRepository(CsvRepository $csvRepository)
156
    {
157
        $this->csvRepository = $csvRepository;
158
    }
159
160
    /**
161
     * @param CsvTypeRepository $csvTypeRepository
162
     */
163
    public function setCsvTypeRepository(CsvTypeRepository $csvTypeRepository)
164
    {
165
        $this->csvTypeRepository = $csvTypeRepository;
166
    }
167
168
    /**
169
     * @param OrderRepository $orderRepository
170
     */
171
    public function setOrderRepository(OrderRepository $orderRepository)
172
    {
173
        $this->orderRepository = $orderRepository;
174
    }
175
176
    /**
177
     * @param CustomerRepository $customerRepository
178
     */
179
    public function setCustomerRepository(CustomerRepository $customerRepository)
180
    {
181
        $this->customerRepository = $customerRepository;
182
    }
183
184
    /**
185
     * @param ProductRepository $productRepository
186
     */
187
    public function setProductRepository(ProductRepository $productRepository)
188
    {
189
        $this->productRepository = $productRepository;
190
    }
191
192
    /**
193
     * @param EntityManagerInterface $entityManager
194
     */
195
    public function setEntityManager(EntityManagerInterface $entityManager)
196
    {
197
        $this->entityManager = $entityManager;
198
    }
199
200
    /**
201
     * @return EntityManagerInterface
202
     */
203
    public function getEntityManager()
204
    {
205
        return $this->entityManager;
206
    }
207
208
    /**
209
     * @param QueryBuilder $qb
210
     */
211 4
    public function setExportQueryBuilder(QueryBuilder $qb)
212
    {
213 4
        $this->qb = $qb;
214
    }
215
216
    /**
217
     * Csv種別からServiceの初期化を行う.
218
     *
219
     * @param $CsvType|integer
220
     */
221 5
    public function initCsvType($CsvType)
222
    {
223 5
        if ($CsvType instanceof CsvType) {
224
            $this->CsvType = $CsvType;
225
        } else {
226 5
            $this->CsvType = $this->csvTypeRepository->find($CsvType);
227
        }
228
229
        $criteria = [
230 5
            'CsvType' => $CsvType,
231
            'enabled' => true,
232
        ];
233
        $orderBy = [
234 5
            'sort_no' => 'ASC',
235
        ];
236 5
        $this->Csvs = $this->csvRepository->findBy($criteria, $orderBy);
237
    }
238
239
    /**
240
     * @return Csv[]
241
     */
242 4
    public function getCsvs()
243
    {
244 4
        return $this->Csvs;
245
    }
246
247
    /**
248
     * ヘッダ行を出力する.
249
     * このメソッドを使う場合は, 事前にinitCsvType($CsvType)で初期化しておく必要がある.
250
     */
251 4
    public function exportHeader()
252
    {
253 4
        if (is_null($this->CsvType) || is_null($this->Csvs)) {
254
            throw new \LogicException('init csv type incomplete.');
255
        }
256
257 4
        $row = [];
258 4
        foreach ($this->Csvs as $Csv) {
259 4
            $row[] = $Csv->getDispName();
260
        }
261
262 4
        $this->fopen();
263 4
        $this->fputcsv($row);
264 4
        $this->fclose();
265
    }
266
267
    /**
268
     * クエリビルダにもとづいてデータ行を出力する.
269
     * このメソッドを使う場合は, 事前にsetExportQueryBuilder($qb)で出力対象のクエリビルダをわたしておく必要がある.
270
     *
271
     * @param \Closure $closure
272
     */
273 4
    public function exportData(\Closure $closure)
274
    {
275 4
        if (is_null($this->qb) || is_null($this->entityManager)) {
276
            throw new \LogicException('query builder not set.');
277
        }
278
279 4
        $this->fopen();
280
281 4
        $query = $this->qb->getQuery();
282 4
        foreach ($query->getResult() as $iteratableResult) {
283 4
            $closure($iteratableResult, $this);
284 4
            $this->entityManager->detach($iteratableResult);
285 4
            $query->free();
286 4
            flush();
287
        }
288
289 4
        $this->fclose();
290
    }
291
292
    /**
293
     * CSV出力項目と比較し, 合致するデータを返す.
294
     *
295
     * @param \Eccube\Entity\Csv $Csv
296
     * @param $entity
297
     *
298
     * @return string|null
299
     */
300 4
    public function getData(Csv $Csv, $entity)
301
    {
302
        // エンティティ名が一致するかどうかチェック.
303 4
        $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
304 4
        $entityName = ClassUtils::getClass($entity);
305 4
        if ($csvEntityName !== $entityName) {
306 2
            return null;
307
        }
308
309
        // カラム名がエンティティに存在するかどうかをチェック.
310 4
        if (!$entity->offsetExists($Csv->getFieldName())) {
311 2
            return null;
312
        }
313
314
        // データを取得.
315 4
        $data = $entity->offsetGet($Csv->getFieldName());
316
317
        // one to one の場合は, dtb_csv.referece_field_nameと比較し, 合致する結果を取得する.
318 4
        if ($data instanceof \Eccube\Entity\AbstractEntity) {
319 4
            if (EntityUtil::isNotEmpty($data)) {
320 4
                return $data->offsetGet($Csv->getReferenceFieldName());
321
            }
322 4
        } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
323
            // one to manyの場合は, カンマ区切りに変換する.
324
            $array = [];
325
            foreach ($data as $elem) {
326
                if (EntityUtil::isNotEmpty($elem)) {
327
                    $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
328
                }
329
            }
330
331
            return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
332 4
        } elseif ($data instanceof \DateTime) {
333
            // datetimeの場合は文字列に変換する.
334 3
            return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
335
        } else {
336
            // スカラ値の場合はそのまま.
337 4
            return $data;
338
        }
339
340
        return null;
341
    }
342
343
    /**
344
     * 文字エンコーディングの変換を行うコールバック関数を返す.
345
     *
346
     * @return \Closure
347
     */
348 5
    public function getConvertEncodhingCallback()
349
    {
350 5
        $config = $this->eccubeConfig;
351
352 5
        return function ($value) use ($config) {
353 5
            return mb_convert_encoding(
354 5
                (string) $value, $config['eccube_csv_export_encoding'], 'UTF-8'
355
            );
356 5
        };
357
    }
358
359 5
    public function fopen()
360
    {
361 5
        if (is_null($this->fp) || $this->closed) {
362 3
            $this->fp = fopen('php://output', 'w');
363
        }
364
    }
365
366
    /**
367
     * @param $row
368
     */
369 5
    public function fputcsv($row)
370
    {
371 5
        if (is_null($this->convertEncodingCallBack)) {
372 5
            $this->convertEncodingCallBack = $this->getConvertEncodhingCallback();
373
        }
374
375 5
        fputcsv($this->fp, array_map($this->convertEncodingCallBack, $row), $this->eccubeConfig['eccube_csv_export_separator']);
376
    }
377
378 5
    public function fclose()
379
    {
380 5
        if (!$this->closed) {
381 5
            fclose($this->fp);
382 5
            $this->closed = true;
383
        }
384
    }
385
386
    /**
387
     * 受注検索用のクエリビルダを返す.
388
     *
389
     * @param Request $request
390
     *
391
     * @return \Doctrine\ORM\QueryBuilder
392
     */
393 1 View Code Duplication
    public function getOrderQueryBuilder(Request $request)
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...
394
    {
395 1
        $session = $request->getSession();
396 1
        $builder = $this->formFactory
397 1
            ->createBuilder(SearchOrderType::class);
398 1
        $searchForm = $builder->getForm();
399
400 1
        $viewData = $session->get('eccube.admin.order.search', []);
401 1
        $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
402
403
        // 受注データのクエリビルダを構築.
404 1
        $qb = $this->orderRepository
405 1
            ->getQueryBuilderBySearchDataForAdmin($searchData);
406
407 1
        return $qb;
408
    }
409
410
    /**
411
     * 会員検索用のクエリビルダを返す.
412
     *
413
     * @param Request $request
414
     *
415
     * @return \Doctrine\ORM\QueryBuilder
416
     */
417 1 View Code Duplication
    public function getCustomerQueryBuilder(Request $request)
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...
418
    {
419 1
        $session = $request->getSession();
420 1
        $builder = $this->formFactory
421 1
            ->createBuilder(SearchProductType::class);
422 1
        $searchForm = $builder->getForm();
423
424 1
        $viewData = $session->get('eccube.admin.customer.search', []);
425 1
        $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
426
427
        // 会員データのクエリビルダを構築.
428 1
        $qb = $this->customerRepository
429 1
            ->getQueryBuilderBySearchData($searchData);
430
431 1
        return $qb;
432
    }
433
434
    /**
435
     * 商品検索用のクエリビルダを返す.
436
     *
437
     * @param Request $request
438
     *
439
     * @return \Doctrine\ORM\QueryBuilder
440
     */
441 View Code Duplication
    public function getProductQueryBuilder(Request $request)
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...
442
    {
443
        $session = $request->getSession();
444
        $builder = $this->formFactory
445
            ->createBuilder(SearchProductType::class);
446
        $searchForm = $builder->getForm();
447
448
        $viewData = $session->get('eccube.admin.product.search', []);
449
        $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
450
451
        // 商品データのクエリビルダを構築.
452
        $qb = $this->productRepository
453
            ->getQueryBuilderBySearchDataForAdmin($searchData);
454
455
        return $qb;
456
    }
457
}
458