/modules/Application/src/Application/Feed/Importer/Csv.php

https://bitbucket.org/delta98/csv-consumer · PHP · 273 lines · 120 code · 38 blank · 115 comment · 9 complexity · 55b809fe4a0a09820e74375501d841b5 MD5 · raw file

  1. <?php
  2. /**
  3. * CSV Consumer Application
  4. *
  5. * @author Jason Brown <jason.brown.delta@gmail.com>
  6. */
  7. namespace Application\Feed\Importer;
  8. use Application\Feed\Data;
  9. use Application\Feed\Importer\ImportInterface;
  10. use Application\Feed\OptionsProviderInterface;
  11. use Zend\Stdlib\ArrayUtils;
  12. /**
  13. * Class CsvImporter
  14. * @package Application\Service
  15. * @TODO Cache processedData
  16. */
  17. class Csv implements ImportInterface, OptionsProviderInterface
  18. {
  19. /**
  20. * @var mixed
  21. */
  22. protected $filePath;
  23. /**
  24. * @var resource
  25. */
  26. protected $resource;
  27. /**
  28. * @var array
  29. */
  30. protected $options = array();
  31. /**
  32. * CSV Column Headers
  33. *
  34. * @var array
  35. */
  36. protected $columnHeaders = array();
  37. /**
  38. * Processed feed data
  39. *
  40. * @var array
  41. */
  42. protected $processedData = array();
  43. /**
  44. * Import Data
  45. *
  46. * @return mixed
  47. */
  48. public function import()
  49. {
  50. // Check File was opened successfully
  51. if($this->open())
  52. {
  53. // Process file
  54. $this->process();
  55. // Close Handle
  56. $this->close();
  57. // Check contents were processed successfully
  58. if(sizeof($this->getProcessedData()) > 0)
  59. {
  60. // Return a valid Feed Data object
  61. return new Data($this->getProcessedData());
  62. }
  63. }
  64. return false;
  65. }
  66. /**
  67. * Set File Path
  68. *
  69. * @param $filePath
  70. * @return \Application\Feed\Importer\Csv $this
  71. */
  72. public function setFilePath($filePath)
  73. {
  74. $this->filePath = $filePath;
  75. return $this;
  76. }
  77. /**
  78. * Get File Path
  79. */
  80. public function getFilePath()
  81. {
  82. return $this->filePath;
  83. }
  84. /**
  85. * Set Resource used to open file
  86. *
  87. * @see http://php.net/manual/en/function.fgetcsv.php
  88. * @param resource $resource
  89. */
  90. public function setResource($resource)
  91. {
  92. $this->resource = $resource;
  93. }
  94. /**
  95. * @return resource
  96. */
  97. public function getResource()
  98. {
  99. return $this->resource;
  100. }
  101. /**
  102. * Set Importer Options
  103. *
  104. * @param array $options
  105. * @return mixed|void
  106. * @throws \Exception
  107. */
  108. public function setOptions(array $options)
  109. {
  110. $this->options = $options;
  111. // Assign required params
  112. if(isset($this->options['file_path']))
  113. {
  114. // Check file path exists
  115. $this->setFilePath($this->options['file_path']);
  116. }else{
  117. throw new \Exception('Required option: file_path not provided');
  118. }
  119. }
  120. /**
  121. * Get Importer Options
  122. *
  123. * @return mixed
  124. */
  125. public function getOptions()
  126. {
  127. return $this->options;
  128. }
  129. /**
  130. * @return array
  131. */
  132. public function getColumnHeaders()
  133. {
  134. return $this->columnHeaders;
  135. }
  136. /**
  137. * Get the processed data
  138. *
  139. * @return array
  140. */
  141. public function getProcessedData()
  142. {
  143. return $this->processedData;
  144. }
  145. /**
  146. * Reset File Importer - clears processed column headers and file contents
  147. */
  148. public function reset()
  149. {
  150. $this->columnHeaders = array();
  151. $this->processedFile = array();
  152. }
  153. /**
  154. * Opens CSV File using provided mode
  155. *
  156. * @param string $mode
  157. * @return bool|resource
  158. */
  159. protected function open($mode = 'r')
  160. {
  161. // Open file using path and mode
  162. $resource = @fopen($this->getFilePath(), $mode);
  163. // Check for a valid resource
  164. if($resource !== false)
  165. {
  166. $this->setResource($resource);
  167. }else{
  168. return false;
  169. }
  170. return $this->getResource();
  171. }
  172. /**
  173. * Closes Resource
  174. */
  175. protected function close()
  176. {
  177. // Check for a resource to close
  178. if(!is_null($this->resource))
  179. {
  180. fclose($this->resource);
  181. }
  182. }
  183. /**
  184. * Processes provided file into a header/row associate array
  185. */
  186. protected function process()
  187. {
  188. // Get Resource Handle
  189. $handle = $this->getResource();
  190. // Flag to determine if headers have been set
  191. $headersSet = false;
  192. // Loop through each row within the provided file
  193. while (($line = fgetcsv($handle)) !== false)
  194. {
  195. // Determine if Headers were set, if not set them
  196. if($headersSet == false)
  197. {
  198. $this->columnHeaders = $line;
  199. $headersSet = true;
  200. }else{
  201. // Process Column Header and associate line value with that header
  202. $this->processedData[] = $this->_processAssociateLineWithColumnHeaders($this->columnHeaders, $line);
  203. }
  204. }
  205. }
  206. /**
  207. * Processes Column Header and splits underscore values into an associate array
  208. * before associating line value with header
  209. *
  210. * @param $columnHeaders
  211. * @param $line
  212. * @return array
  213. */
  214. protected function _processAssociateLineWithColumnHeaders($columnHeaders, $line)
  215. {
  216. $processedLines = array();
  217. // Create an associate array if underscored column header is detected
  218. foreach($columnHeaders as $key => $header)
  219. {
  220. // Check for an underscore in the Column Header
  221. if(preg_match('/^[a-z0-9]+_[a-z0-9]+$/i', ucwords($header)))
  222. {
  223. // Split header by underscore to separate strings
  224. $headers = explode('_', $header);
  225. // Form associate array with key being first string from split array
  226. $processedLine[$headers[0]] = array($headers[1] => $line[$key]);
  227. }else{
  228. $processedLine = array($header => $line[$key]);
  229. }
  230. // Merge newly processed line with all the other processed lines
  231. $processedLines = ArrayUtils::merge($processedLines, $processedLine);
  232. }
  233. return $processedLines;
  234. }
  235. }