Completed
Push — dev/store-tests ( 3e9e56...714865 )
by Kiyotaka
05:47
created

CsvExportService::getConvertEncodingCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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