Completed
Push — 4.0 ( 268f2c...88f012 )
by Hideki
05:48 queued 10s
created

src/Eccube/Service/CsvExportService.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of EC-CUBE
5
 *
6
 * Copyright(c) EC-CUBE CO.,LTD. All Rights Reserved.
7
 *
8
 * http://www.ec-cube.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 76
     */
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 76
    ) {
134 76
        $this->entityManager = $entityManager;
135 76
        $this->csvRepository = $csvRepository;
136 76
        $this->csvTypeRepository = $csvTypeRepository;
137 76
        $this->orderRepository = $orderRepository;
138 76
        $this->shippingRepository = $shippingRepository;
139 76
        $this->customerRepository = $customerRepository;
140 76
        $this->eccubeConfig = $eccubeConfig;
141 76
        $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 4
     */
212
    public function setExportQueryBuilder(QueryBuilder $qb)
213 4
    {
214
        $this->qb = $qb;
215
    }
216
217
    /**
218
     * Csv種別からServiceの初期化を行う.
219
     *
220
     * @param $CsvType|integer
221 5
     */
222
    public function initCsvType($CsvType)
223 5
    {
224
        if ($CsvType instanceof CsvType) {
225
            $this->CsvType = $CsvType;
226 5
        } else {
227
            $this->CsvType = $this->csvTypeRepository->find($CsvType);
228
        }
229
230 5
        $criteria = [
231
            'CsvType' => $CsvType,
232
            'enabled' => true,
233
        ];
234 5
        $orderBy = [
235
            'sort_no' => 'ASC',
236 5
        ];
237
        $this->Csvs = $this->csvRepository->findBy($criteria, $orderBy);
238
    }
239
240
    /**
241
     * @return Csv[]
242 4
     */
243
    public function getCsvs()
244 4
    {
245
        return $this->Csvs;
246
    }
247
248
    /**
249
     * ヘッダ行を出力する.
250
     * このメソッドを使う場合は, 事前にinitCsvType($CsvType)で初期化しておく必要がある.
251 4
     */
252
    public function exportHeader()
253 4
    {
254
        if (is_null($this->CsvType) || is_null($this->Csvs)) {
255
            throw new \LogicException('init csv type incomplete.');
256
        }
257 4
258 4
        $row = [];
259 4
        foreach ($this->Csvs as $Csv) {
260
            $row[] = $Csv->getDispName();
261
        }
262 4
263 4
        $this->fopen();
264 4
        $this->fputcsv($row);
265
        $this->fclose();
266
    }
267
268
    /**
269
     * クエリビルダにもとづいてデータ行を出力する.
270
     * このメソッドを使う場合は, 事前にsetExportQueryBuilder($qb)で出力対象のクエリビルダをわたしておく必要がある.
271
     *
272
     * @param \Closure $closure
273 4
     */
274
    public function exportData(\Closure $closure)
275 4
    {
276
        if (is_null($this->qb) || is_null($this->entityManager)) {
277
            throw new \LogicException('query builder not set.');
278
        }
279 4
280
        $this->fopen();
281 4
282 4
        $query = $this->qb->getQuery();
283 4
        foreach ($query->getResult() as $iterableResult) {
284 4
            $closure($iterableResult, $this);
285 4
            $this->entityManager->detach($iterableResult);
286 4
            $query->free();
287
            flush();
288
        }
289 4
290
        $this->fclose();
291
    }
292
293
    /**
294
     * CSV出力項目と比較し, 合致するデータを返す.
295
     *
296
     * @param \Eccube\Entity\Csv $Csv
297
     * @param $entity
298
     *
299
     * @return string|null
300 4
     */
301
    public function getData(Csv $Csv, $entity)
302
    {
303 4
        // エンティティ名が一致するかどうかチェック.
304 4
        $csvEntityName = str_replace('\\\\', '\\', $Csv->getEntityName());
305 4
        $entityName = ClassUtils::getClass($entity);
306 2
        if ($csvEntityName !== $entityName) {
307
            return null;
308
        }
309
310 4
        // カラム名がエンティティに存在するかどうかをチェック.
311 2
        if (!$entity->offsetExists($Csv->getFieldName())) {
312
            return null;
313
        }
314
315 4
        // データを取得.
316
        $data = $entity->offsetGet($Csv->getFieldName());
317
318 4
        // one to one の場合は, dtb_csv.reference_field_name, 合致する結果を取得する.
319 4
        if ($data instanceof \Eccube\Entity\AbstractEntity) {
320 4
            if (EntityUtil::isNotEmpty($data)) {
0 ignored issues
show
Deprecated Code introduced by
The method Eccube\Util\EntityUtil::isNotEmpty() has been deprecated.

This method has been deprecated.

Loading history...
321
                return $data->offsetGet($Csv->getReferenceFieldName());
322 4
            }
323
        } elseif ($data instanceof \Doctrine\Common\Collections\Collection) {
324
            // one to manyの場合は, カンマ区切りに変換する.
325
            $array = [];
326
            foreach ($data as $elem) {
327
                if (EntityUtil::isNotEmpty($elem)) {
0 ignored issues
show
Deprecated Code introduced by
The method Eccube\Util\EntityUtil::isNotEmpty() has been deprecated.

This method has been deprecated.

Loading history...
328
                    $array[] = $elem->offsetGet($Csv->getReferenceFieldName());
329
                }
330
            }
331
332 4
            return implode($this->eccubeConfig['eccube_csv_export_multidata_separator'], $array);
333
        } elseif ($data instanceof \DateTime) {
334 3
            // datetimeの場合は文字列に変換する.
335
            return $data->format($this->eccubeConfig['eccube_csv_export_date_format']);
336
        } else {
337 4
            // スカラ値の場合はそのまま.
338
            return $data;
339
        }
340
341
        return null;
342
    }
343
344
    /**
345
     * 文字エンコーディングの変換を行うコールバック関数を返す.
346
     *
347
     * @return \Closure
348 5
     */
349
    public function getConvertEncodingCallback()
350 5
    {
351
        $config = $this->eccubeConfig;
352 5
353 5
        return function ($value) use ($config) {
354 5
            return mb_convert_encoding(
355
                (string) $value, $config['eccube_csv_export_encoding'], 'UTF-8'
356 5
            );
357
        };
358
    }
359 5
360
    public function fopen()
361 5
    {
362 3
        if (is_null($this->fp) || $this->closed) {
363
            $this->fp = fopen('php://output', 'w');
364
        }
365
    }
366
367
    /**
368
     * @param $row
369 5
     */
370
    public function fputcsv($row)
371 5
    {
372 5
        if (is_null($this->convertEncodingCallBack)) {
373
            $this->convertEncodingCallBack = $this->getConvertEncodingCallback();
374
        }
375 5
376
        fputcsv($this->fp, array_map($this->convertEncodingCallBack, $row), $this->eccubeConfig['eccube_csv_export_separator']);
377
    }
378 5
379
    public function fclose()
380 5
    {
381 5
        if (!$this->closed) {
382 5
            fclose($this->fp);
383
            $this->closed = true;
384
        }
385
    }
386
387
    /**
388
     * 受注検索用のクエリビルダを返す.
389
     *
390
     * @param Request $request
391
     *
392
     * @return \Doctrine\ORM\QueryBuilder
393 1
     */
394 View Code Duplication
    public function getOrderQueryBuilder(Request $request)
395 1
    {
396 1
        $session = $request->getSession();
397 1
        $builder = $this->formFactory
398 1
            ->createBuilder(SearchOrderType::class);
399
        $searchForm = $builder->getForm();
400 1
401 1
        $viewData = $session->get('eccube.admin.order.search', []);
402
        $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
403
404 1
        // 受注データのクエリビルダを構築.
405 1
        $qb = $this->orderRepository
406
            ->getQueryBuilderBySearchDataForAdmin($searchData);
407 1
408
        return $qb;
409
    }
410
411
    /**
412
     * 会員検索用のクエリビルダを返す.
413
     *
414
     * @param Request $request
415
     *
416
     * @return \Doctrine\ORM\QueryBuilder
417 1
     */
418 View Code Duplication
    public function getCustomerQueryBuilder(Request $request)
419 1
    {
420 1
        $session = $request->getSession();
421 1
        $builder = $this->formFactory
422 1
            ->createBuilder(SearchCustomerType::class);
423
        $searchForm = $builder->getForm();
424 1
425 1
        $viewData = $session->get('eccube.admin.customer.search', []);
426
        $searchData = FormUtil::submitAndGetData($searchForm, $viewData);
427
428 1
        // 会員データのクエリビルダを構築.
429 1
        $qb = $this->customerRepository
430
            ->getQueryBuilderBySearchData($searchData);
431 1
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)
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