/home/mip/public_html/img/credit/datatables/Imports.tar
ModelImporter.php 0000644 00000010070 15152066013 0010034 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\SkipsEmptyRows;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithBatchInserts;
use Maatwebsite\Excel\Concerns\WithCalculatedFormulas;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithEvents;
use Maatwebsite\Excel\Concerns\WithFormatData;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithProgressBar;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Events\AfterBatch;
use Maatwebsite\Excel\HasEventBus;
use Maatwebsite\Excel\Row;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class ModelImporter
{
use HasEventBus;
/**
* @var ModelManager
*/
private $manager;
/**
* @param ModelManager $manager
*/
public function __construct(ModelManager $manager)
{
$this->manager = $manager;
}
/**
* @param Worksheet $worksheet
* @param ToModel $import
* @param int|null $startRow
* @param string|null $endColumn
*
* @throws \Maatwebsite\Excel\Validators\ValidationException
*/
public function import(Worksheet $worksheet, ToModel $import, int $startRow = 1)
{
if ($startRow > $worksheet->getHighestRow()) {
return;
}
if ($import instanceof WithEvents) {
$this->registerListeners($import->registerEvents());
}
$headingRow = HeadingRowExtractor::extract($worksheet, $import);
$headerIsGrouped = HeadingRowExtractor::extractGrouping($headingRow, $import);
$batchSize = $import instanceof WithBatchInserts ? $import->batchSize() : 1;
$endRow = EndRowFinder::find($import, $startRow, $worksheet->getHighestRow());
$progessBar = $import instanceof WithProgressBar;
$withMapping = $import instanceof WithMapping;
$withCalcFormulas = $import instanceof WithCalculatedFormulas;
$formatData = $import instanceof WithFormatData;
$withValidation = $import instanceof WithValidation && method_exists($import, 'prepareForValidation');
$endColumn = $import instanceof WithColumnLimit ? $import->endColumn() : null;
$this->manager->setRemembersRowNumber(method_exists($import, 'rememberRowNumber'));
$i = 0;
$batchStartRow = $startRow;
foreach ($worksheet->getRowIterator($startRow, $endRow) as $spreadSheetRow) {
$i++;
$row = new Row($spreadSheetRow, $headingRow, $headerIsGrouped);
if (!$import instanceof SkipsEmptyRows || !$row->isEmpty($withCalcFormulas)) {
$rowArray = $row->toArray(null, $withCalcFormulas, $formatData, $endColumn);
if ($import instanceof SkipsEmptyRows && method_exists($import, 'isEmptyWhen') && $import->isEmptyWhen($rowArray)) {
continue;
}
if ($withValidation) {
$rowArray = $import->prepareForValidation($rowArray, $row->getIndex());
}
if ($withMapping) {
$rowArray = $import->map($rowArray);
}
$this->manager->add(
$row->getIndex(),
$rowArray
);
// Flush each batch.
if (($i % $batchSize) === 0) {
$this->flush($import, $batchSize, $batchStartRow);
$batchStartRow += $i;
$i = 0;
if ($progessBar) {
$import->getConsoleOutput()->progressAdvance($batchSize);
}
}
}
}
if ($i > 0) {
// Flush left-overs.
$this->flush($import, $batchSize, $batchStartRow);
}
}
private function flush(ToModel $import, int $batchSize, int $startRow)
{
$this->manager->flush($import, $batchSize > 1);
$this->raise(new AfterBatch($this->manager, $import, $batchSize, $startRow));
}
}
Persistence/CascadePersistManager.php 0000644 00000005477 15152066013 0013745 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports\Persistence;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Transactions\TransactionHandler;
/** @todo */
class CascadePersistManager
{
/**
* @var TransactionHandler
*/
private $transaction;
/**
* @param TransactionHandler $transaction
*/
public function __construct(TransactionHandler $transaction)
{
$this->transaction = $transaction;
}
/**
* @param Model $model
* @return bool
*/
public function persist(Model $model): bool
{
return ($this->transaction)(function () use ($model) {
return $this->save($model);
});
}
/**
* @param Model $model
* @return bool
*/
private function save(Model $model): bool
{
if (!$model->save()) {
return false;
}
foreach ($model->getRelations() as $relationName => $models) {
$models = array_filter(
$models instanceof Collection ? $models->all() : [$models]
);
$relation = $model->{$relationName}();
if ($relation instanceof BelongsTo) {
if (!$this->persistBelongsTo($relation, $models)) {
return false;
}
}
if ($relation instanceof BelongsToMany) {
if (!$this->persistBelongsToMany($relation, $models)) {
return false;
}
}
}
// We need to save the model again to
// make sure all updates are performed.
$model->save();
return true;
}
/**
* @param BelongsTo $relation
* @param array $models
* @return bool
*/
private function persistBelongsTo(BelongsTo $relation, array $models): bool
{
// With belongs to, we first need to save all relations,
// so we can use their foreign key to attach to the relation.
foreach ($models as $model) {
// Cascade any relations that this child model may have.
if (!$this->save($model)) {
return false;
}
$relation->associate($model);
}
return true;
}
/**
* @param BelongsToMany $relation
* @param array $models
* @return bool
*/
private function persistBelongsToMany(BelongsToMany $relation, array $models): bool
{
foreach ($models as $model) {
$relation->save($model);
// Cascade any relations that this child model may have.
if (!$this->save($model)) {
return false;
}
}
return true;
}
}
HeadingRowFormatter.php 0000644 00000004475 15152066013 0011201 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;
use InvalidArgumentException;
class HeadingRowFormatter
{
/**
* @const string
*/
const FORMATTER_NONE = 'none';
/**
* @const string
*/
const FORMATTER_SLUG = 'slug';
/**
* @var string
*/
protected static $formatter;
/**
* @var callable[]
*/
protected static $customFormatters = [];
/**
* @var array
*/
protected static $defaultFormatters = [
self::FORMATTER_NONE,
self::FORMATTER_SLUG,
];
/**
* @param array $headings
* @return array
*/
public static function format(array $headings): array
{
return (new Collection($headings))->map(function ($value, $key) {
return static::callFormatter($value, $key);
})->toArray();
}
/**
* @param string $name
*/
public static function default(string $name = null)
{
if (null !== $name && !isset(static::$customFormatters[$name]) && !in_array($name, static::$defaultFormatters, true)) {
throw new InvalidArgumentException(sprintf('Formatter "%s" does not exist', $name));
}
static::$formatter = $name;
}
/**
* @param string $name
* @param callable $formatter
*/
public static function extend(string $name, callable $formatter)
{
static::$customFormatters[$name] = $formatter;
}
/**
* Reset the formatter.
*/
public static function reset()
{
static::default();
}
/**
* @param mixed $value
* @return mixed
*/
protected static function callFormatter($value, $key=null)
{
static::$formatter = static::$formatter ?? config('excel.imports.heading_row.formatter', self::FORMATTER_SLUG);
// Call custom formatter
if (isset(static::$customFormatters[static::$formatter])) {
$formatter = static::$customFormatters[static::$formatter];
return $formatter($value, $key);
}
if (empty($value)) {
return $key;
}
if (static::$formatter === self::FORMATTER_SLUG) {
return Str::slug($value, '_');
}
// No formatter (FORMATTER_NONE)
return $value;
}
}
ModelManager.php 0000644 00000014257 15152066013 0007620 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Maatwebsite\Excel\Concerns\PersistRelations;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithUpsertColumns;
use Maatwebsite\Excel\Concerns\WithUpserts;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Exceptions\RowSkippedException;
use Maatwebsite\Excel\Imports\Persistence\CascadePersistManager;
use Maatwebsite\Excel\Validators\RowValidator;
use Maatwebsite\Excel\Validators\ValidationException;
use Throwable;
class ModelManager
{
/**
* @var array
*/
private $rows = [];
/**
* @var RowValidator
*/
private $validator;
/**
* @var bool
*/
private $remembersRowNumber = false;
/**
* @var CascadePersistManager
*/
private $cascade;
/**
* @param RowValidator $validator
*/
public function __construct(RowValidator $validator, CascadePersistManager $cascade)
{
$this->validator = $validator;
$this->cascade = $cascade;
}
/**
* @param int $row
* @param array $attributes
*/
public function add(int $row, array $attributes)
{
$this->rows[$row] = $attributes;
}
/**
* @param bool $remembersRowNumber
*/
public function setRemembersRowNumber(bool $remembersRowNumber)
{
$this->remembersRowNumber = $remembersRowNumber;
}
/**
* @param ToModel $import
* @param bool $massInsert
*
* @throws ValidationException
*/
public function flush(ToModel $import, bool $massInsert = false)
{
if ($import instanceof WithValidation) {
$this->validateRows($import);
}
if ($massInsert) {
$this->massFlush($import);
} else {
$this->singleFlush($import);
}
$this->rows = [];
}
/**
* @param ToModel $import
* @param array $attributes
* @param int|null $rowNumber
* @return Model[]|Collection
*/
public function toModels(ToModel $import, array $attributes, $rowNumber = null): Collection
{
if ($this->remembersRowNumber) {
$import->rememberRowNumber($rowNumber);
}
return Collection::wrap($import->model($attributes));
}
/**
* @param ToModel $import
*/
private function massFlush(ToModel $import)
{
$this->rows()
->flatMap(function (array $attributes, $index) use ($import) {
return $this->toModels($import, $attributes, $index);
})
->mapToGroups(function ($model) {
return [\get_class($model) => $this->prepare($model)->getAttributes()];
})
->each(function (Collection $models, string $model) use ($import) {
try {
/* @var Model $model */
if ($import instanceof WithUpserts) {
$model::query()->upsert(
$models->toArray(),
$import->uniqueBy(),
$import instanceof WithUpsertColumns ? $import->upsertColumns() : null
);
return;
}
$model::query()->insert($models->toArray());
} catch (Throwable $e) {
$this->handleException($import, $e);
}
});
}
/**
* @param ToModel $import
*/
private function singleFlush(ToModel $import)
{
$this
->rows()
->each(function (array $attributes, $index) use ($import) {
$this->toModels($import, $attributes, $index)->each(function (Model $model) use ($import) {
try {
if ($import instanceof WithUpserts) {
$model->upsert(
$model->getAttributes(),
$import->uniqueBy(),
$import instanceof WithUpsertColumns ? $import->upsertColumns() : null
);
return;
}
if ($import instanceof PersistRelations) {
$this->cascade->persist($model);
} else {
$model->saveOrFail();
}
} catch (Throwable $e) {
$this->handleException($import, $e);
}
});
});
}
/**
* @param Model $model
* @return Model
*/
private function prepare(Model $model): Model
{
if ($model->usesTimestamps()) {
$time = $model->freshTimestamp();
$updatedAtColumn = $model->getUpdatedAtColumn();
// If model has updated at column and not manually provided.
if ($updatedAtColumn && null === $model->{$updatedAtColumn}) {
$model->setUpdatedAt($time);
}
$createdAtColumn = $model->getCreatedAtColumn();
// If model has created at column and not manually provided.
if ($createdAtColumn && null === $model->{$createdAtColumn}) {
$model->setCreatedAt($time);
}
}
return $model;
}
/**
* @param WithValidation $import
*
* @throws ValidationException
*/
private function validateRows(WithValidation $import)
{
try {
$this->validator->validate($this->rows, $import);
} catch (RowSkippedException $e) {
foreach ($e->skippedRows() as $row) {
unset($this->rows[$row]);
}
}
}
/**
* @return Collection
*/
private function rows(): Collection
{
return new Collection($this->rows);
}
private function handleException(ToModel $import, Throwable $e): void
{
if (!$import instanceof SkipsOnError) {
throw $e;
}
$import->onError($e);
}
}
EndRowFinder.php 0000644 00000001464 15152066013 0007607 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\WithLimit;
class EndRowFinder
{
/**
* @param object|WithLimit $import
* @param int $startRow
* @param int|null $highestRow
* @return int|null
*/
public static function find($import, int $startRow = null, int $highestRow = null)
{
if (!$import instanceof WithLimit) {
return null;
}
$limit = $import->limit();
if ($limit > $highestRow) {
return null;
}
// When no start row given,
// use the first row as start row.
$startRow = $startRow ?? 1;
// Subtract 1 row from the start row, so a limit
// of 1 row, will have the same start and end row.
return ($startRow - 1) + $limit;
}
}
HeadingRowExtractor.php 0000644 00000004765 15152066013 0011213 0 ustar 00 <?php
namespace Maatwebsite\Excel\Imports;
use Maatwebsite\Excel\Concerns\WithColumnLimit;
use Maatwebsite\Excel\Concerns\WithGroupedHeadingRow;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithStartRow;
use Maatwebsite\Excel\Row;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class HeadingRowExtractor
{
/**
* @const int
*/
const DEFAULT_HEADING_ROW = 1;
/**
* @param WithHeadingRow|mixed $importable
* @return int
*/
public static function headingRow($importable): int
{
return method_exists($importable, 'headingRow')
? $importable->headingRow()
: self::DEFAULT_HEADING_ROW;
}
/**
* @param WithHeadingRow|mixed $importable
* @return int
*/
public static function determineStartRow($importable): int
{
if ($importable instanceof WithStartRow) {
return $importable->startRow();
}
// The start row is the row after the heading row if we have one!
return $importable instanceof WithHeadingRow
? self::headingRow($importable) + 1
: self::DEFAULT_HEADING_ROW;
}
/**
* @param Worksheet $worksheet
* @param WithHeadingRow|mixed $importable
* @return array
*/
public static function extract(Worksheet $worksheet, $importable): array
{
if (!$importable instanceof WithHeadingRow) {
return [];
}
$headingRowNumber = self::headingRow($importable);
$rows = iterator_to_array($worksheet->getRowIterator($headingRowNumber, $headingRowNumber));
$headingRow = head($rows);
$endColumn = $importable instanceof WithColumnLimit ? $importable->endColumn() : null;
return HeadingRowFormatter::format((new Row($headingRow))->toArray(null, false, false, $endColumn));
}
/**
* @param array $headingRow
* @param WithGroupedHeadingRow|mixed $importable
* @return array
*/
public static function extractGrouping($headingRow, $importable)
{
$headerIsGrouped = array_fill(0, count($headingRow), false);
if (!$importable instanceof WithGroupedHeadingRow) {
return $headerIsGrouped;
}
array_walk($headerIsGrouped, function (&$value, $key) use ($headingRow) {
if (array_count_values($headingRow)[$headingRow[$key]] > 1) {
$value = true;
}
});
return $headerIsGrouped;
}
}