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) |
|
|
|
|
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) |
|
|
|
|
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
|
|
|
|
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.