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