| 
									
										
										
										
											2016-06-10 21:00:00 +02:00
										 |  |  | <?php | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * CsvImporter.php | 
					
						
							|  |  |  |  * Copyright (C) 2016 thegrumpydictator@gmail.com | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This software may be modified and distributed under the terms | 
					
						
							|  |  |  |  * of the MIT license.  See the LICENSE file for details. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | declare(strict_types = 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace FireflyIII\Import\Importer; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | use FireflyIII\Import\Converter\ConverterInterface; | 
					
						
							|  |  |  | use FireflyIII\Import\ImportEntry; | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  | use FireflyIII\Import\Specifics\SpecificInterface; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | use FireflyIII\Models\ImportJob; | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  | use Illuminate\Support\Collection; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | use League\Csv\Reader; | 
					
						
							|  |  |  | use Log; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-10 21:00:00 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Class CsvImporter | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * @package FireflyIII\Import\Importer | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | class CsvImporter implements ImporterInterface | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |     /** @var  Collection */ | 
					
						
							|  |  |  |     public $collection; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     /** @var  ImportJob */ | 
					
						
							|  |  |  |     public $job; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * CsvImporter constructor. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->collection = new Collection; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Run the actual import | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |      * @return Collection | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |     public function createImportEntries(): Collection | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |         $config  = $this->job->configuration; | 
					
						
							|  |  |  |         $content = $this->job->uploadFileContents(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // create CSV reader.
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         $reader = Reader::createFromString($content); | 
					
						
							| 
									
										
										
										
											2016-08-11 08:00:02 +02:00
										 |  |  |         $reader->setDelimiter($config['delimiter']); | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         $start   = $config['has-headers'] ? 1 : 0; | 
					
						
							|  |  |  |         $results = $reader->fetch(); | 
					
						
							| 
									
										
										
										
											2016-08-13 14:22:40 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         Log::notice('Building importable objects from CSV file.'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |         foreach ($results as $index => $row) { | 
					
						
							|  |  |  |             if ($index >= $start) { | 
					
						
							| 
									
										
										
										
											2016-08-13 14:22:40 +02:00
										 |  |  |                 $line = $index + 1; | 
					
						
							| 
									
										
										
										
											2016-08-11 10:21:32 +02:00
										 |  |  |                 Log::debug('----- import entry build start --'); | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |                 Log::debug(sprintf('Now going to import row %d.', $index)); | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |                 $importEntry = $this->importSingleRow($index, $row); | 
					
						
							| 
									
										
										
										
											2016-08-13 14:22:40 +02:00
										 |  |  |                 $this->collection->put($line, $importEntry); | 
					
						
							| 
									
										
										
										
											2016-08-26 06:43:38 +02:00
										 |  |  |                 /** | 
					
						
							|  |  |  |                  * 1. Build import entry. | 
					
						
							|  |  |  |                  * 2. Validate import entry. | 
					
						
							|  |  |  |                  * 3. Store journal. | 
					
						
							|  |  |  |                  * 4. Run rules. | 
					
						
							|  |  |  |                  */ | 
					
						
							|  |  |  |                 $this->job->addTotalSteps(4); | 
					
						
							| 
									
										
										
										
											2016-08-13 21:51:01 +02:00
										 |  |  |                 $this->job->addStepsDone(1); | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         Log::debug(sprintf('Import collection contains %d entries', $this->collection->count())); | 
					
						
							| 
									
										
										
										
											2016-08-13 14:22:40 +02:00
										 |  |  |         Log::notice(sprintf('Built %d importable object(s) from your CSV file.', $this->collection->count())); | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         return $this->collection; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * @param ImportJob $job | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function setJob(ImportJob $job) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->job = $job; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2016-08-06 09:31:32 +02:00
										 |  |  |      * @param int   $index | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |      * @param array $row | 
					
						
							|  |  |  |      * | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |      * @return ImportEntry | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |     private function importSingleRow(int $index, array $row): ImportEntry | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         // create import object. This is where each entry ends up.
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |         $object = new ImportEntry; | 
					
						
							| 
									
										
										
										
											2016-08-06 09:31:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 15:10:03 +02:00
										 |  |  |         Log::debug(sprintf('Now at row %d', $index)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 09:31:32 +02:00
										 |  |  |         // set some vars:
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |         $object->setUser($this->job->user); | 
					
						
							|  |  |  |         $config = $this->job->configuration; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-14 08:34:51 +02:00
										 |  |  |         // hash the row:
 | 
					
						
							|  |  |  |         $hash = hash('sha256', json_encode($row)); | 
					
						
							|  |  |  |         $object->importValue('hash', 100, $hash); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |         // and this is the point where the specifix go to work.
 | 
					
						
							|  |  |  |         foreach ($config['specifics'] as $name => $enabled) { | 
					
						
							|  |  |  |             /** @var SpecificInterface $specific */ | 
					
						
							|  |  |  |             $specific = app('FireflyIII\Import\Specifics\\' . $name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // it returns the row, possibly modified:
 | 
					
						
							|  |  |  |             $row = $specific->run($row); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($row as $rowIndex => $value) { | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |             // find the role for this column:
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |             $role           = $config['column-roles'][$rowIndex] ?? '_ignore'; | 
					
						
							|  |  |  |             $doMap          = $config['column-do-mapping'][$rowIndex] ?? false; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |             $converterClass = config('csv.import_roles.' . $role . '.converter'); | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |             $mapping        = $config['column-mapping-config'][$rowIndex] ?? []; | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |             /** @var ConverterInterface $converter */ | 
					
						
							|  |  |  |             $converter = app('FireflyIII\\Import\\Converter\\' . $converterClass); | 
					
						
							|  |  |  |             // set some useful values for the converter:
 | 
					
						
							|  |  |  |             $converter->setMapping($mapping); | 
					
						
							|  |  |  |             $converter->setDoMap($doMap); | 
					
						
							|  |  |  |             $converter->setUser($this->job->user); | 
					
						
							|  |  |  |             $converter->setConfig($config); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // run the converter for this value:
 | 
					
						
							|  |  |  |             $convertedValue = $converter->convert($value); | 
					
						
							|  |  |  |             $certainty      = $converter->getCertainty(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // log it.
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |             Log::debug('Value ', ['index' => $rowIndex, 'value' => $value, 'role' => $role]); | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             // store in import entry:
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  |             Log::debug('Going to import', ['role' => $role, 'value' => $value, 'certainty' => $certainty]); | 
					
						
							|  |  |  |             $object->importValue($role, $certainty, $convertedValue); | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 09:27:09 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-10 18:49:16 +02:00
										 |  |  |         return $object; | 
					
						
							| 
									
										
										
										
											2016-07-15 22:26:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-06 06:28:21 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2016-08-12 15:10:03 +02:00
										 |  |  | } |