1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* TechDivision\Import\Cli\FileMerger |
5
|
|
|
* |
6
|
|
|
* NOTICE OF LICENSE |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the Open Software License (OSL 3.0) |
9
|
|
|
* that is available through the world-wide-web at this URL: |
10
|
|
|
* http://opensource.org/licenses/osl-3.0.php |
11
|
|
|
* |
12
|
|
|
* PHP version 5 |
13
|
|
|
* |
14
|
|
|
* @author Tim Wagner <[email protected]> |
15
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
16
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
17
|
|
|
* @link https://github.com/techdivision/import-cli-simple |
18
|
|
|
* @link http://www.techdivision.com |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace TechDivision\Import\Cli; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* Prototype for a class that merges multiple CSV files. |
25
|
|
|
* |
26
|
|
|
* This class SHOULD only be used for testing purposes, as it reads the content of all files |
27
|
|
|
* into the memory and merges them. This results in huge memory consumption and has to be |
28
|
|
|
* refactored. |
29
|
|
|
* |
30
|
|
|
* @author Tim Wagner <[email protected]> |
31
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
32
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
33
|
|
|
* @link https://github.com/techdivision/import-cli-simple |
34
|
|
|
* @link http://www.techdivision.com |
35
|
|
|
*/ |
36
|
|
|
class FileMerger |
37
|
|
|
{ |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* The columns that has to be ignored when merging the files |
41
|
|
|
* |
42
|
|
|
* @var array |
43
|
|
|
*/ |
44
|
|
|
protected $ignoreColumns = array( |
45
|
|
|
'base_image', |
46
|
|
|
'base_image_label', |
47
|
|
|
'small_image', |
48
|
|
|
'small_image_label', |
49
|
|
|
'thumbnail_image', |
50
|
|
|
'thumbnail_image_label', |
51
|
|
|
'swatch_image', |
52
|
|
|
'swatch_image_label', |
53
|
|
|
'additional_images', |
54
|
|
|
'additional_image_label' |
55
|
|
|
); |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* The array with the headers. |
59
|
|
|
* |
60
|
|
|
* @var array |
61
|
|
|
*/ |
62
|
|
|
protected $headers = array(); |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* The array with the rows. |
66
|
|
|
* |
67
|
|
|
* @var array |
68
|
|
|
*/ |
69
|
|
|
protected $rows = array(); |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Initialize the the merger instance. |
73
|
|
|
* |
74
|
|
|
* @param string $srcDir The source directory |
75
|
|
|
* @param string $destFilename The target filename |
76
|
|
|
* |
77
|
|
|
* @return void |
78
|
|
|
*/ |
79
|
|
|
public function merge($srcDir, $destFilename) |
80
|
|
|
{ |
81
|
|
|
|
82
|
|
|
// load the CSV files from the source directory |
83
|
|
|
$srcFilenames = glob(sprintf('%s/*.csv', $srcDir)); |
84
|
|
|
|
85
|
|
|
// iterate over all found CSV files |
86
|
|
|
foreach ($srcFilenames as $srcFilename) { |
87
|
|
|
// open the CSV file |
88
|
|
|
if ($fh = fopen($srcFilename, 'r')) { |
89
|
|
|
// log a message |
90
|
|
|
error_log(sprintf('Now open file "%s"', $srcFilename)); |
91
|
|
|
// initialize the row counter |
92
|
|
|
$rowCounter = 0; |
93
|
|
|
|
94
|
|
|
// read the lines |
95
|
|
|
while (($data = fgetcsv($fh, 0, ",")) !== false) { |
96
|
|
|
// raise the row counter |
97
|
|
|
$rowCounter++; |
98
|
|
|
|
99
|
|
|
// initialize the headers, if we're on the first line |
100
|
|
|
if ($rowCounter === 1) { |
101
|
|
|
$this->headers = array_flip($data); |
102
|
|
|
continue; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
// iterate over the headers |
106
|
|
|
foreach ($this->headers as $headerName => $headerValue) { |
107
|
|
|
// set a default price of 1, if the column has NO price |
108
|
|
|
if ($headerName === 'price' && $data[$headerValue] !== '') { |
109
|
|
|
$data[$headerValue] = 1; |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
// query whether or not the field has to be ignored |
113
|
|
|
if (in_array($headerName, $this->ignoreColumns)) { |
114
|
|
|
$this->rows[$data[$this->headers['sku']]][$data[$this->headers['store_view_code']]][$headerValue] = null; |
115
|
|
|
} elseif ($data[$headerValue] !== '') { |
116
|
|
|
$this->rows[$data[$this->headers['sku']]][$data[$this->headers['store_view_code']]][$headerValue] = $data[$headerValue]; |
117
|
|
|
} elseif ($data[$headerValue] === '' && !isset($this->rows[$data[$this->headers['sku']]][$data[$this->headers['store_view_code']]][$headerValue])) { |
118
|
|
|
$this->rows[$data[$this->headers['sku']]][$data[$this->headers['store_view_code']]][$headerValue] = $data[$headerValue]; |
119
|
|
|
} else { |
120
|
|
|
// do not override with empty value |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
// log a message with the number of rows processed |
125
|
|
|
error_log(sprintf('Successfully processed line "%s", "%d"', $srcFilename, $rowCounter)); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
// close the file finally |
129
|
|
|
fclose($fh); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
// open the destination file |
134
|
|
|
$fh = fopen(sprintf('%s/%s', $srcDir, $destFilename, 'w')); |
135
|
|
|
|
136
|
|
|
// write the headers |
137
|
|
|
fputcsv($fh, array_keys($this->headers)); |
138
|
|
|
|
139
|
|
|
// write the rows to the target file |
140
|
|
|
foreach ($this->rows as $skus) { |
141
|
|
|
foreach ($skus as $storeViewCode) { |
142
|
|
|
fputcsv($fh, $storeViewCode); |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
// close the destination file |
147
|
|
|
fclose($fh); |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
// Example how to invoke the file merger: |
152
|
|
|
// php -f src/FileMerger.php projects/sample-data/data/products/add-update import-products_20171220-1234_01.csv |
153
|
|
|
|
154
|
|
|
// initialize the source directory |
155
|
|
|
$srcDir = __DIR__; |
156
|
|
|
|
157
|
|
|
// query whether or not a source directoy has been passed |
158
|
|
|
if (isset($argv[1]) && is_dir($argv[1])) { |
159
|
|
|
$srcDir = $argv[1]; |
160
|
|
|
} else { |
161
|
|
|
throw new \Exception(sprintf('Please specify a source directory as first argument')); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
// query whether or not a target filename has been passed |
165
|
|
|
if (!isset($argv[2])) { |
166
|
|
|
throw new \Exception(sprintf('Please specify a target filename as second argument')); |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
// intialize the instance and merge the files |
170
|
|
|
$merger = new FileMerger(); |
171
|
|
|
$merger->merge($srcDir, argv[2]); |
172
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.