winter/modules/backend/models/ImportModel.php
2015-07-21 20:45:02 +10:00

162 lines
3.9 KiB
PHP

<?php namespace Backend\Models;
use Model;
use League\Csv\Reader as CsvReader;
/**
* Model used for importing data
*
* @package october\backend
* @author Alexey Bobkov, Samuel Georges
*/
abstract class ImportModel extends Model
{
use \October\Rain\Database\Traits\Validation;
/**
* The attributes that aren't mass assignable.
* @var array
*/
protected $guarded = [];
/**
* Relations
*/
public $attachOne = [
'import_file' => ['System\Models\File']
];
protected $resultStats = [
'updated' => 0,
'created' => 0,
'errors' => [],
'warnings' => [],
'skipped' => []
];
/**
* Called when data is being imported.
*/
abstract public function importData($results, $sessionKey = null);
public function importDataFromColumnMatch($matches, $sessionKey = null, $options = [])
{
$path = $this->getImportFilePath($sessionKey);
$data = $this->processImportData($path, $matches, $options);
return $this->importData($data, $sessionKey);
}
/**
* Converts column index to database column map to an array containing
* database column names and values pulled from the CSV file.
* Eg:
* [0 => [first_name], 1 => [last_name]]
*
* Will return:
* [first_name => Joe, last_name => Blogs],
* [first_name => Harry, last_name => Potter],
* [...]
*
* @return array
*/
protected function processImportData($filePath, $matches, $options)
{
extract(array_merge([
'firstRowTitles' => true
], $options));
$reader = CsvReader::createFromPath($filePath);
if ($firstRowTitles) {
$reader->setOffset(1);
}
$result = [];
$contents = $reader->fetchAll();
foreach ($contents as $row) {
$result[] = $this->processImportRow($row, $matches);
}
return $result;
}
/**
* Converts a single row of CSV data to the column map.
* @return array
*/
protected function processImportRow($rowData, $matches)
{
$newRow = [];
foreach ($matches as $columnIndex => $dbNames) {
$value = array_get($rowData, $columnIndex);
foreach ((array) $dbNames as $dbName) {
$newRow[$dbName] = $value;
}
}
return $newRow;
}
/**
* Returns an attached imported file local path, if available.
* @return string
*/
public function getImportFilePath($sessionKey = null)
{
$file = $this
->import_file()
->withDeferred($sessionKey)
->first();
if (!$file) {
return null;
}
return $file->getLocalPath();
}
//
// Result logging
//
public function getResultStats()
{
$this->resultStats['errorCount'] = count($this->resultStats['errors']);
$this->resultStats['warningCount'] = count($this->resultStats['warnings']);
$this->resultStats['skippedCount'] = count($this->resultStats['skipped']);
$this->resultStats['hasMessages'] = (
$this->resultStats['errorCount'] > 0 ||
$this->resultStats['warningCount'] > 0 ||
$this->resultStats['skippedCount'] > 0
);
return (object) $this->resultStats;
}
protected function logUpdated()
{
$this->resultStats['updated']++;
}
protected function logCreated()
{
$this->resultStats['created']++;
}
protected function logError($rowIndex, $message)
{
$this->resultStats['errors'][$rowIndex] = $message;
}
protected function logWarning($rowIndex, $message)
{
$this->resultStats['warnings'][$rowIndex] = $message;
}
protected function logSkipped($rowIndex, $message)
{
$this->resultStats['skipped'][$rowIndex] = $message;
}
}