initial commit
[namibia] / module / Utility / src / Utility / Import / CsvSemicolon.php
1 <?php
2 namespace Utility\Import;
3
4 class CsvSemicolon implements ImportInterface
5 {
6         private $_isExtractedFile = false;
7         private $_fileName;
8         private $_fileHandle;
9         private $_delimiter = ';';
10         private $_enclosure = '"';
11         private $_escape = '\\';
12         private $_recordLength = 0;
13         private $_specialFields = array();
14         protected $_headers = array();
15
16         const FETCH_LAZY  = 1;
17         const FETCH_ASSOC = 2;
18         const FETCH_BOTH  = 3;
19
20         public function __construct($file, $firstLineIsHeaders = true)
21         {
22                 $this->_fileName = $file;
23                 if (!file_exists($this->_fileName))
24                 {
25                         throw new \Exception('File ' . $this->_fileName . ' not found');
26                 }
27                 $this->handleZipArchive();
28                 $this->_fileHandle = fopen($this->_fileName, 'r');
29                 if ($firstLineIsHeaders)
30                 {
31                         $this->_headers = $this->getRecord();
32                 }
33         }
34
35         /**
36          * @throws \Exception
37          */
38         protected function handleZipArchive()
39         {
40                 if (strpos($this->_fileName, '.zip'))
41                 {
42                         #-> Extract csv from zip archive.
43                         $this->processZipFile();
44                 }
45         }
46
47         /**
48          * @throws \Exception
49          */
50         protected function processZipFile()
51         {
52                 $zip = new \ZipArchive();
53                 if ($this->zipArchiveSuccessfullyOpened($zip))
54                 {
55                         $this->extractZipFile($zip);
56
57                         #-> Find the csv file.
58                         $this->establishFilePath();
59                 }
60                 else
61                 {
62                         throw new \Exception('CSV Importer Error: Could not open zip archive!');
63                 }
64         }
65
66         /**
67          * @param $zip
68          * @return bool
69          */
70         protected function zipArchiveSuccessfullyOpened(\ZipArchive $zip)
71         {
72                 return true === $zip->open($this->_fileName);
73         }
74
75         /**
76          * @param $zip
77          * @throws \Exception
78          */
79         protected function extractZipFile(\ZipArchive $zip)
80         {
81                 if (false === $zip->extractTo(getcwd() . '/data/extract'))
82                 {
83                         throw new \Exception('CSV Import Utility: Could open but not extract zip archive!');
84                 }
85                 $zip->close();
86         }
87
88         protected function establishFilePath()
89         {
90                 $fileList    = scandir(getcwd() . '/data/extract/');
91                 $ignoreFiles = array(
92                         '.'          => true,
93                         '..'         => true,
94                         '.gitignore' => true
95                 );
96                 $numFiles    = 0;
97                 foreach ($fileList as $fileEntry)
98                 {
99                         $numFiles = $this->processFileEntry($ignoreFiles, $fileEntry, $numFiles);
100                 }
101                 $this->ensureSingleCsvFileInZip($numFiles);
102                 $this->_isExtractedFile = true;
103         }
104
105         /**
106          * @param $ignoreFiles
107          * @param $fileEntry
108          * @param $numFiles
109          * @return mixed
110          */
111         protected function processFileEntry($ignoreFiles, $fileEntry, $numFiles)
112         {
113                 if (isset($ignoreFiles[$fileEntry]))
114                 {
115                         return $numFiles;
116                 }
117                 if (strpos($fileEntry, '.csv'))
118                 {
119                         return $this->getFilePath($fileEntry, $numFiles);
120                 }
121                 else
122                 {
123                         unlink(getcwd() . '/data/extract/' . $fileEntry);
124                         return $numFiles;
125                 }
126         }
127
128         /**
129          * @param $fileEntry
130          * @param $numFiles
131          * @return mixed
132          */
133         protected function getFilePath($fileEntry, $numFiles)
134         {
135                 $numFiles++;
136                 if (1 < $numFiles)
137                 {
138                         unlink($this->_fileName);
139                 }
140                 $this->_fileName = getcwd() . '/data/extract/' . $fileEntry;
141                 return $numFiles;
142         }
143
144         /**
145          * @param $numFiles
146          * @throws \Exception
147          */
148         protected function ensureSingleCsvFileInZip($numFiles)
149         {
150                 if (1 < $numFiles)
151                 {
152                         unlink($this->_fileName);
153                         throw new \Exception('CSV Importer Error: More than 1 csv file in zip archive!');
154                 }
155                 if (0 == $numFiles)
156                 {
157                         unlink($this->_fileName);
158                         throw new \Exception('CSV Importer Error: 0 csv files in zip archive!');
159                 }
160         }
161
162         public function getHeaders()
163         {
164                 return $this->_headers;
165         }
166
167         public function setDelimiter($delimiter)
168         {
169                 $this->_delimiter = $delimiter;
170                 if (!empty($this->_headers))
171                 {
172                         $this->reset();
173                         $this->_headers = $this->getRecord(self::FETCH_LAZY);
174                 }
175         }
176
177         public function setEnclosure($enclosure)
178         {
179                 $this->_enclosure = $enclosure;
180         }
181
182         public function setEscape($escape)
183         {
184                 $this->_escape = $escape;
185         }
186
187         public function setRecordLength($length)
188         {
189                 $this->_recordLength = $length;
190         }
191
192         /**
193          * Gets the next record in the file
194          * @return array
195          */
196         public function getRecord($method = self::FETCH_BOTH)
197         {
198                 $record = fgetcsv($this->_fileHandle, $this->_recordLength, $this->_delimiter, $this->_enclosure, $this->_escape);
199
200         \Utility\Debug::errorLog('$record', $record);
201
202                 if($record === false)
203                 {
204                         return false;
205                 }
206
207                 $fieldsCount = count($record);
208                 foreach ($this->_specialFields as $key => $value)
209                 {
210                         $record[$key] = $value->parse($record[$key]);
211                 }
212                 if (($method & self::FETCH_ASSOC) && !empty($this->_headers))
213                 {
214                         for($i = 0; $i < count($this->_headers); $i++)
215                                 $record[$this->_headers[$i]] = $record[$i];
216                 }
217                 if (!($method & self::FETCH_LAZY))
218                 {
219                         for ($i = 0; $i < $fieldsCount; $i++)
220                         {
221                                 unset($record[$i]);
222                         }
223                 }
224
225                 return $record;
226         }
227
228         public function reset()
229         {
230                 fseek($this->_fileHandle, 0);
231         }
232
233         public function setField($fieldNr, ImportInterface $class)
234         {
235                 $this->_specialFields[$fieldNr - 1] = $class;
236         }
237
238         public function __destruct()
239         {
240                 fclose($this->_fileHandle);
241                 if ($this->_isExtractedFile)
242                 {
243                         unlink($this->_fileName);
244                 }
245         }
246 }