diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 9916fe1..4bbf2f6 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -12,12 +12,14 @@ jobs: strategy: fail-fast: false matrix: - php: [8.2, 8.1, 8.0] - laravel: [9.*] + php: [8.4, 8.3] + laravel: [13.*, 12.*] dependency-version: [prefer-stable] include: - - laravel: 9.* - testbench: 7.* + - laravel: 12.* + testbench: 10.* + - laravel: 13.* + testbench: 11.* steps: - uses: actions/checkout@v6 @@ -25,11 +27,13 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: ${{ matrix.php }} coverage: none - name: Install composer dependencies - uses: ramsey/composer-install@v4 + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.dependency-version }} --prefer-dist --no-interaction - name: Run PHPStan - run: ./vendor/bin/phpstan --error-format=github + run: ./vendor/bin/phpstan analyse --error-format=github diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ac5a706..8466816 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -13,19 +13,14 @@ jobs: fail-fast: true matrix: os: [ubuntu-latest] - php: [8.4, 8.3, 8.2, 8.1] - laravel: [10.*, 9.*] + php: [8.5, 8.4, 8.3] + laravel: [13.*, 12.*] stability: [prefer-lowest, prefer-stable] include: - - laravel: 9.* - testbench: 7.* - carbon: ^2.63 - - laravel: 10.* - testbench: 8.* - carbon: ^2.63 - exclude: - - laravel: 10.* - php: 8.0 + - laravel: 12.* + testbench: 10.* + - laravel: 13.* + testbench: 11.* name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} @@ -40,24 +35,16 @@ jobs: extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo coverage: none - - name: Set Minimum PHP 8.2 Versions - uses: nick-fields/retry@v4 - with: - timeout_minutes: 5 - max_attempts: 5 - command: composer require guzzlehttp/psr7:~2.4 --no-interaction --no-update - if: matrix.php >= 8.2 - - name: Setup problem matchers run: | echo "::add-matcher::${{ runner.tool_cache }}/php.json" echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Install dependencies run: | - composer require "laravel/framework:${{ matrix.laravel }}" "nesbot/carbon:${{ matrix.carbon }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: List Installed Dependencies run: composer show -D - name: Execute tests - run: vendor/bin/pest + run: vendor/bin/pest diff --git a/classAliases.php b/classAliases.php index 608377f..77d54e9 100644 --- a/classAliases.php +++ b/classAliases.php @@ -1,3 +1,5 @@ ',', - /* |-------------------------------------------------------------------------- | Max Upload File Size diff --git a/phpstan.neon.dist b/phpstan.neon.dist index df0e9d7..74f9d56 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -2,16 +2,12 @@ includes: - phpstan-baseline.neon parameters: - level: 6 + level: 5 paths: - src - config - database + - tests/Models/User.php tmpDir: build/phpstan - checkMissingIterableValueType: false - checkGenericClassInNonGenericObjectType: false bootstrapFiles: - classAliases.php - - - diff --git a/phpunit.xml.dist b/phpunit.xml.dist index d4b27e9..95a7540 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,39 +1,19 @@ - - - - - - - tests - - - - - ./src - - - - - - - - - - + + + + + + + tests + + + + + + + + ./src + + diff --git a/resources/views/components/button.blade.php b/resources/views/components/button.blade.php index 96b6938..9c806a2 100644 --- a/resources/views/components/button.blade.php +++ b/resources/views/components/button.blade.php @@ -1,6 +1,6 @@ \ No newline at end of file + diff --git a/resources/views/livewire/tailwindcss/csv-importer.blade.php b/resources/views/livewire/tailwindcss/csv-importer.blade.php index 1de466c..19733a4 100644 --- a/resources/views/livewire/tailwindcss/csv-importer.blade.php +++ b/resources/views/livewire/tailwindcss/csv-importer.blade.php @@ -1,4 +1,4 @@ -
+
@@ -78,7 +78,7 @@ {{ $columnLabels[$column] ?? ucfirst(str_replace(['_', '-'], ' ', $column)) }}{{ in_array('columnsToMap.' . $column, array_keys($requiredColumns)) ? '*': ''}}
- @foreach ($fileHeaders as $fileHeader) diff --git a/src/Commands/LiveSetupCommand.php b/src/Commands/LiveSetupCommand.php index 51521c2..a710da5 100644 --- a/src/Commands/LiveSetupCommand.php +++ b/src/Commands/LiveSetupCommand.php @@ -3,7 +3,6 @@ namespace Askdkc\LivewireCsv\Commands; use Illuminate\Console\Command; -use Illuminate\Filesystem\Filesystem; use Illuminate\Support\Facades\Artisan; class LiveSetupCommand extends Command @@ -17,24 +16,24 @@ public function handle(): void $this->info('Preparing Livewire-CSV necessary migrations / 必要なマイグレーションを準備します'); $this->comment('Publishing migration... / マイグレーションファイル準備中'); - if(!$this->migrationExists('create_jobs_table')) { - Artisan::call("queue:table"); + if (! $this->migrationExists('create_jobs_table')) { + Artisan::call('queue:table'); $this->comment('Migration Jobs created successfully / Jobsテーブル作成'); } - if(!$this->migrationExists('create_job_batches_table')) { - Artisan::call("queue:batches-table"); + if (! $this->migrationExists('create_job_batches_table')) { + Artisan::call('queue:batches-table'); $this->comment('Migration Job Batches created successfully / Job Batches テーブル作成'); } - if(!$this->migrationExists('create_csv_imports_table')) { - $this->callSilently("vendor:publish", [ - '--tag' => "livewire-csv-migrations", + if (! $this->migrationExists('create_csv_imports_table')) { + $this->callSilently('vendor:publish', [ + '--tag' => 'livewire-csv-migrations', ]); $this->comment('Migration Csv Imports created successfully / Csv Importsテーブル作成'); } - if ($this->confirm('Would you like to set your locale to Japanese? / 言語を日本語にしますか?')) { + if ($this->confirm('Would you like to set your locale to Japanese? / 言語を日本語にしますか?')) { $this->info('config/app.phpのlocaleをjaにします'); // Read the contents of the file into a string $configfile = file_get_contents(base_path('config/app.php')); @@ -52,7 +51,7 @@ public function handle(): void '--tag' => 'livewire-csv-config', ]); - $this->info("Done! / 完了!"); + $this->info('Done! / 完了!'); if ($this->confirm('Would you like to run the migrations now? / マイグレーションを実行しますか?')) { $this->comment('Running migrations... / 実行中...'); @@ -61,7 +60,7 @@ public function handle(): void } if ($this->confirm("Would you like to star our repo on GitHub? \n GitHubリポジトリにスターの御協力をお願いします🙏", true)) { - $repoUrl = "https://github.com/askdkc/livewire-csv"; + $repoUrl = 'https://github.com/askdkc/livewire-csv'; if (PHP_OS_FAMILY == 'Darwin') { exec("open {$repoUrl}"); @@ -77,16 +76,18 @@ public function handle(): void } } - private function migrationExists(string $filename): Bool + private function migrationExists(string $filename): bool { $path = database_path('migrations/'); $files = scandir($path); $pos = false; foreach ($files as $value) { $pos = strpos($value, $filename); - if($pos !== false) return true; + if ($pos !== false) { + return true; + } } + return false; } - } diff --git a/src/Concerns/HasCsvImports.php b/src/Concerns/HasCsvImports.php index e8bc116..1ced888 100644 --- a/src/Concerns/HasCsvImports.php +++ b/src/Concerns/HasCsvImports.php @@ -10,7 +10,7 @@ trait HasCsvImports /** * Has imports relationship * - * @return \Illuminate\Database\Eloquent\Relations\HasMany + * @return HasMany */ public function imports(): HasMany { diff --git a/src/Concerns/HasCsvProperties.php b/src/Concerns/HasCsvProperties.php index d4f71a9..aa188fc 100644 --- a/src/Concerns/HasCsvProperties.php +++ b/src/Concerns/HasCsvProperties.php @@ -6,13 +6,14 @@ use Illuminate\Support\MessageBag; use League\Csv\Reader; use League\Csv\Statement; +use League\Csv\SyntaxError; use League\Csv\TabularDataReader; /** * Askdkc\LivewireCsv\Concerns\HasCsvProperties * * @property Reader $readCsv - * @property \League\Csv\TabularDataReader $csvRecords + * @property TabularDataReader $csvRecords */ trait HasCsvProperties { @@ -20,8 +21,6 @@ trait HasCsvProperties /** * Read CSV Property - * - * @return Reader */ public function getReadCsvProperty(): Reader { @@ -30,8 +29,6 @@ public function getReadCsvProperty(): Reader /** * Get CSV Records Property - * - * @return TabularDataReader */ public function getCsvRecordsProperty(): TabularDataReader { @@ -40,8 +37,6 @@ public function getCsvRecordsProperty(): TabularDataReader /** * Handle CSV Information properties from the given file - * - * @return array|\Illuminate\Support\MessageBag */ public function handleCsvProperties(): array|MessageBag { @@ -50,7 +45,7 @@ public function handleCsvProperties(): array|MessageBag $fileRowCount = $this->csvRecords->count(); return [$fileHeaders, $fileRowCount]; - } catch (\League\Csv\SyntaxError $exception) { + } catch (SyntaxError $exception) { Log::warning($exception->getMessage()); return $this->addError( diff --git a/src/Concerns/InteractsWithColumns.php b/src/Concerns/InteractsWithColumns.php index 678efb5..87c7ece 100644 --- a/src/Concerns/InteractsWithColumns.php +++ b/src/Concerns/InteractsWithColumns.php @@ -6,8 +6,6 @@ trait InteractsWithColumns { /** * Converts the columnsToMap property into an associative array. - * - * @return array */ protected function mapThroughColumns(): array { @@ -16,14 +14,12 @@ protected function mapThroughColumns(): array } return collect($this->columnsToMap) - ->mapWithKeys(fn ($column): array => [$column => '']) - ->toArray(); + ->mapWithKeys(fn ($column): array => [$column => '']) + ->toArray(); } /** * Maps requiredColumns property into columnsToMap required state. - * - * @return array */ protected function mapThroughRequiredColumns(): array { @@ -36,5 +32,4 @@ protected function mapThroughRequiredColumns(): array return ['columnsToMap.'.$column => 'required']; })->toArray(); } - } diff --git a/src/Concerns/InteractsWithCsvFiles.php b/src/Concerns/InteractsWithCsvFiles.php index 8fe9d16..0a7d3bd 100644 --- a/src/Concerns/InteractsWithCsvFiles.php +++ b/src/Concerns/InteractsWithCsvFiles.php @@ -8,9 +8,6 @@ trait InteractsWithCsvFiles { /** * Read CSV File. - * - * @param string $path - * @return Reader */ protected function readCSV(string $path): Reader { @@ -22,7 +19,7 @@ protected function readCSV(string $path): Reader ->skipEmptyRecords(); // Check File Type - if(config('livewire_csv.file_type') === 'tsv') { + if (config('livewire_csv.file_type') === 'tsv') { $csv->setDelimiter("\t"); } diff --git a/src/Facades/LivewireCsv.php b/src/Facades/LivewireCsv.php index 27356ee..b3c0ba5 100644 --- a/src/Facades/LivewireCsv.php +++ b/src/Facades/LivewireCsv.php @@ -11,4 +11,3 @@ protected static function getFacadeAccessor() return 'livewire-csv'; } } - diff --git a/src/Http/Livewire/CsvImporter.php b/src/Http/Livewire/CsvImporter.php index 01e85ed..85b438d 100644 --- a/src/Http/Livewire/CsvImporter.php +++ b/src/Http/Livewire/CsvImporter.php @@ -2,57 +2,51 @@ namespace Askdkc\LivewireCsv\Http\Livewire; -use Illuminate\Support\Str; -use Livewire\Component; - -use Livewire\WithFileUploads; use Askdkc\LivewireCsv\Concerns; +use Askdkc\LivewireCsv\Facades\LivewireCsv; +use Askdkc\LivewireCsv\Jobs\ImportCsv; +use Askdkc\LivewireCsv\Tests\Models\User; +use Askdkc\LivewireCsv\Utilities\ChunkIterator; use Illuminate\Support\Collection; -use Illuminate\Support\MessageBag; use Illuminate\Support\Facades\Bus; +use Illuminate\Support\MessageBag; +use Illuminate\Support\Str; use Illuminate\Validation\Validator; -use Askdkc\LivewireCsv\Jobs\ImportCsv; -use Askdkc\LivewireCsv\Facades\LivewireCsv; +use Livewire\Component; +use Livewire\WithFileUploads; + use function Askdkc\LivewireCsv\csv_view_path; -use Askdkc\LivewireCsv\Utilities\ChunkIterator; class CsvImporter extends Component { - use WithFileUploads; - use Concerns\InteractsWithColumns; use Concerns\HasCsvProperties; + use Concerns\InteractsWithColumns; + use WithFileUploads; /** @var string */ public $model; - /** @var bool */ public bool $open = false; /** @var object */ public $file; - /** @var array */ public array $columnsToMap = []; - /** @var array */ public array $requiredColumns = []; - /** @var array */ public array $columnLabels = []; - /** @var array */ public array $upsertColumns = []; - /** @var array */ public array $fileHeaders = []; - /** @var int */ public int $fileRowCount = 0; /** @var array */ protected $exceptions = [ 'model', 'columnsToMap', 'open', - 'columnLabels', 'requiredColumns','upsertColumns', + 'columnLabels', 'requiredColumns', 'upsertColumns', ]; /** @var array */ @@ -61,7 +55,8 @@ class CsvImporter extends Component ]; // This makes validation message translatable using the package's lang files - protected function messages(): array { + protected function messages(): array + { return [ 'required' => trans('livewire-csv::validation.required'), ]; @@ -76,8 +71,7 @@ public function mount(): void $this->requiredColumns = $this->mapThroughRequiredColumns(); // check if user specified upsert columns - if(!$this->upsertColumns) - { + if (! $this->upsertColumns) { $this->upsertColumns = ['id']; } } @@ -99,7 +93,7 @@ public function import(): void $this->resetExcept($this->exceptions); - $this->emitTo('handle-imports', 'imports.refresh'); + $this->dispatch('imports.refresh')->to(HandleImports::class); } public function toggle(): void @@ -107,7 +101,7 @@ public function toggle(): void $this->open = ! $this->open; } - public function render(): Object + public function render(): object { return view(csv_view_path('csv-importer'), [ 'fileSize' => LivewireCsv::formatFileSize( @@ -118,11 +112,11 @@ public function render(): Object protected function validationAttributes(): array { - $columnMessage = new Collection(); - foreach ($this->requiredColumns as $key => $col) - { + $columnMessage = new Collection; + foreach ($this->requiredColumns as $key => $col) { $columnMessage->push([$key => $this->columnLabels[Str::after($key, 'columnsToMap.')] ?? Str::after($key, 'columnsToMap.')]); } + return $columnMessage->collapse()->toArray(); } @@ -145,7 +139,7 @@ protected function setCsvProperties(): array return $this->withValidator(function (Validator $validator) { $validator->after(function ($validator) { $validator->errors()->merge( - $this->handleCsvProperties()->getMessages() + $this->handleCsvProperties()->getMessages() ); }); })->validate(); @@ -156,30 +150,29 @@ protected function importCsv(): void $import = $this->createNewImport(); $chunks = (new ChunkIterator($this->csvRecords->getIterator(), 10))->get(); - /** @var array $chunks */ $jobs = collect($chunks) - ->map( - fn ($chunk) => new ImportCsv( - $import, - $this->model, - $chunk, - $this->columnsToMap, - $this->upsertColumns - ) - ); + ->map( + fn ($chunk) => new ImportCsv( + $import, + $this->model, + $chunk, + $this->columnsToMap, + $this->upsertColumns + ) + ); Bus::batch($jobs) - ->name('import-csv') - ->finally( - fn () => $import->touch('completed_at') - )->dispatch(); - $this->emit('imports', $jobs); + ->name('import-csv') + ->finally( + fn () => $import->touch('completed_at') + )->dispatch(); + $this->dispatch('imports'); } - protected function createNewImport(): Object + protected function createNewImport(): object { /** - * @var \Askdkc\LivewireCsv\Tests\Models\User */ + * @var User */ $user = auth()->user(); return $user->imports()->create([ diff --git a/src/Http/Livewire/HandleImports.php b/src/Http/Livewire/HandleImports.php index be18dde..2621044 100644 --- a/src/Http/Livewire/HandleImports.php +++ b/src/Http/Livewire/HandleImports.php @@ -2,13 +2,15 @@ namespace Askdkc\LivewireCsv\Http\Livewire; -use function Askdkc\LivewireCsv\csv_view_path; use Askdkc\LivewireCsv\Models\Import; use Illuminate\Contracts\View\Factory; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Collection; +use Illuminate\Foundation\Auth\User; use Livewire\Component; +use function Askdkc\LivewireCsv\csv_view_path; + class HandleImports extends Component { /** @var string */ @@ -26,15 +28,15 @@ public function mount(string $model): void public function getImportsProperty(): Collection { - /** @var \Illuminate\Foundation\Auth\User */ + /** @var User */ $user = auth()->user(); return Import::query() - ->forModel($this->model) - ->forUser($user->id) - ->oldest() - ->unCompleted() - ->get(); + ->forModel($this->model) + ->forUser($user->id) + ->oldest() + ->unCompleted() + ->get(); } public function render(): View|Factory diff --git a/src/Jobs/ImportCsv.php b/src/Jobs/ImportCsv.php index bf06ffd..c0adea9 100644 --- a/src/Jobs/ImportCsv.php +++ b/src/Jobs/ImportCsv.php @@ -13,8 +13,8 @@ class ImportCsv implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; use Batchable; + use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Create a new job instance. @@ -27,8 +27,7 @@ public function __construct( public array $chunk, public array $columns, public array $upsertColumns, - ) { - } + ) {} /** * Execute the job. @@ -40,11 +39,9 @@ public function handle() $importData = []; // swap user specified csv data fields to actual database column names - foreach($this->chunk as $data) - { - $temprow = new Collection(); - foreach ($this->columns as $key => $value) - { + foreach ($this->chunk as $data) { + $temprow = new Collection; + foreach ($this->columns as $key => $value) { $temprow->push([$key => $data[$value] ?? null]); } $importData[] = $temprow->collapse()->toArray(); diff --git a/src/LivewireCsvDirectives.php b/src/LivewireCsvDirectives.php index 6ee7b75..ca632cb 100644 --- a/src/LivewireCsvDirectives.php +++ b/src/LivewireCsvDirectives.php @@ -6,10 +6,8 @@ class LivewireCsvDirectives { /** * Get CSV Styles - * - * @return string */ - public static function csvStyles(): string|null + public static function csvStyles(): ?string { if (config('livewire_csv.layout') == 'tailwindcss') { return self::getTailwindStyle(); @@ -20,8 +18,6 @@ public static function csvStyles(): string|null /** * Get CSV Scripts - * - * @return string */ public static function csvScripts(): string { @@ -32,8 +28,6 @@ public static function csvScripts(): string /** * Get Tailwind Style Path - * - * @return string */ protected static function getTailwindStyle(): string { diff --git a/src/LivewireCsvManager.php b/src/LivewireCsvManager.php index 9394e22..e74b198 100644 --- a/src/LivewireCsvManager.php +++ b/src/LivewireCsvManager.php @@ -6,10 +6,6 @@ class LivewireCsvManager { /** * Get the given size and formated it. - * - * @param int $size - * @param int $precision - * @return string|int */ public function formatFileSize(int $size, int $precision = 2): string|int { @@ -17,11 +13,11 @@ public function formatFileSize(int $size, int $precision = 2): string|int return $size; } - $base = log((int) $size) / log(1024); + $base = (int) floor(log($size) / log(1024)); $suffixes = ['KB', 'MB', 'GB', 'TB']; return round( - pow(1024, $base - floor($base)), $precision - ).$suffixes[floor($base)]; + pow(1024, (log($size) / log(1024)) - $base), $precision + ).$suffixes[$base]; } } diff --git a/src/LivewireCsvServiceProvider.php b/src/LivewireCsvServiceProvider.php index aaef220..3427917 100644 --- a/src/LivewireCsvServiceProvider.php +++ b/src/LivewireCsvServiceProvider.php @@ -46,8 +46,6 @@ public function registeringPackage(): void /** * Configure Livewire CSV Blade components - * - * @return void */ protected function configureComponents(): void { @@ -58,8 +56,6 @@ protected function configureComponents(): void /** * Register livewire components - * - * @return void */ protected function registerLivewireComponents(): void { @@ -70,9 +66,6 @@ protected function registerLivewireComponents(): void /** * Register given component. - * - * @param string $component - * @return void */ protected function registerComponent(string $component): void { @@ -81,8 +74,6 @@ protected function registerComponent(string $component): void /** * Register Livewire CSV blade directives - * - * @return void */ protected function registerBladeDirectives(): void { diff --git a/src/Models/Import.php b/src/Models/Import.php index 38c09c5..da1e8a6 100644 --- a/src/Models/Import.php +++ b/src/Models/Import.php @@ -4,6 +4,7 @@ use Askdkc\LivewireCsv\Scopes; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Carbon; /** * Askdkc\LivewireCsv\Models\Import @@ -15,9 +16,9 @@ * @property string $file_name * @property int $total_rows * @property int $processed_rows - * @property \Illuminate\Support\Carbon|null $completed_at - * @property \Illuminate\Support\Carbon|null $created_at - * @property \Illuminate\Support\Carbon|null $updated_at + * @property Carbon|null $completed_at + * @property Carbon|null $created_at + * @property Carbon|null $updated_at */ class Import extends Model { @@ -33,7 +34,7 @@ class Import extends Model /** * The attributes that aren't mass assignable. * - * @var array|bool + * @var array */ protected $guarded = []; } diff --git a/src/Scopes/ImportScope.php b/src/Scopes/ImportScope.php index e5d8397..eaad0dd 100644 --- a/src/Scopes/ImportScope.php +++ b/src/Scopes/ImportScope.php @@ -9,8 +9,6 @@ trait ImportScope { /** * Completed Status Scope - * - * @return \Illuminate\Database\Eloquent\Builder */ public function scopeCompleted(Builder $builder): Builder { @@ -19,8 +17,6 @@ public function scopeCompleted(Builder $builder): Builder /** * Not Completed Status Scope - * - * @return \Illuminate\Database\Eloquent\Builder */ public function scopeUnCompleted(Builder $builder): Builder { @@ -29,8 +25,6 @@ public function scopeUnCompleted(Builder $builder): Builder /** * Get the percentage of the model completion - * - * @return int|float */ public function percentageComplete(): int|float { @@ -39,9 +33,6 @@ public function percentageComplete(): int|float /** * Fetch imports based on the given model - * - * @param string $model - * @return \Illuminate\Database\Eloquent\Builder */ public function scopeForModel(Builder $builder, string $model): Builder { @@ -50,9 +41,6 @@ public function scopeForModel(Builder $builder, string $model): Builder /** * Fetch imports on the user id - * - * @param int $user - * @return \Illuminate\Database\Eloquent\Builder */ public function scopeForUser(Builder $builder, int $user): Builder { diff --git a/src/Utilities/ChunkIterator.php b/src/Utilities/ChunkIterator.php index 7935bde..472b78a 100644 --- a/src/Utilities/ChunkIterator.php +++ b/src/Utilities/ChunkIterator.php @@ -18,14 +18,8 @@ */ class ChunkIterator { - /** - * @var Iterator - */ protected Iterator $iterator; - /** - * @var int - */ protected int $chunkSize; public function __construct(Iterator $iterator, int $chunkSize) @@ -36,13 +30,11 @@ public function __construct(Iterator $iterator, int $chunkSize) /** * Chunk the given data - * - * @return Generator */ public function get(): Generator { $this->iterator->rewind(); - + $chunk = []; for ($i = 0; $this->iterator->valid(); $i++) { diff --git a/src/helpers.php b/src/helpers.php index fa683f0..9476ae7 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -5,11 +5,8 @@ if (! function_exists('Askdkc\LivewireCsv\csv_view_path')) { /** * Get the evaluated view content from the livewire view - * - * @param string|null $view - * @return string */ - function csv_view_path(string|null $view): string + function csv_view_path(?string $view): string { return 'livewire-csv::livewire.'.config('livewire_csv.layout').'.'.$view; } diff --git a/tests/CsvImporterTest.php b/tests/CsvImporterTest.php index 0e5e437..e7cfa75 100644 --- a/tests/CsvImporterTest.php +++ b/tests/CsvImporterTest.php @@ -7,6 +7,7 @@ use Illuminate\Bus\PendingBatch; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Bus; + use function Pest\Livewire\livewire; beforeEach(fn () => $this->actingAs(User::factory()->create())); @@ -17,8 +18,8 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->assertSet('model', $model) - ->assertSuccessful(); + ->assertSet('model', $model) + ->assertSuccessful(); }); it('renders import CSV component with model and file', function () { @@ -33,9 +34,9 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSuccessful(); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSuccessful(); }); it('throws a validation error if the csv file empty', function () { @@ -84,13 +85,13 @@ 'model' => $model, 'columnsToMap' => $columnsToMap, ]) - ->assertSet('model', $model) - ->assertSet('columnsToMap', [ - 'name' => '', - 'email' => '', - 'phone' => '', - ]) - ->assertSuccessful(); + ->assertSet('model', $model) + ->assertSet('columnsToMap', [ + 'name' => '', + 'email' => '', + 'phone' => '', + ]) + ->assertSuccessful(); }); it('maps requiredColumns property into columnsToMap required state', function () { @@ -112,12 +113,12 @@ 'columnsToMap' => $columnsToMap, 'requiredColumns' => $requiredColumns, ]) - ->assertSet('model', $model) - ->assertSet('requiredColumns', [ - 'columnsToMap.name' => 'required', - 'columnsToMap.email' => 'required', - 'columnsToMap.phone' => 'required', - ]); + ->assertSet('model', $model) + ->assertSet('requiredColumns', [ + 'columnsToMap.name' => 'required', + 'columnsToMap.email' => 'required', + 'columnsToMap.phone' => 'required', + ]); }); it('maps through columnsLabels for validate attributes', function () { @@ -142,32 +143,32 @@ 'requiredColumns' => $requiredColumns, 'columnLabels' => $columnLabels, ]) - ->assertSet('model', $model) - ->assertSet('columnLabels', [ - 'name' => 'Name', - 'email' => 'Email', - ]); + ->assertSet('model', $model) + ->assertSet('columnLabels', [ + 'name' => 'Name', + 'email' => 'Email', + ]); }); it('returns csv headers & row counts when upload a file', function () { $file = UploadedFile::fake() - ->createWithContent( - 'customers.csv', - file_get_contents('stubs/customers.csv', true) - ); + ->createWithContent( + 'customers.csv', + file_get_contents('stubs/customers.csv', true) + ); $model = Customer::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSet('fileHeaders', [ - 'id', 'first_name', 'last_name', 'email', 'company', 'vip', 'birthday', 'created_at', 'updated_at', - ]) - ->assertSet('fileRowCount', 1000); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSet('fileHeaders', [ + 'id', 'first_name', 'last_name', 'email', 'company', 'vip', 'birthday', 'created_at', 'updated_at', + ]) + ->assertSet('fileRowCount', 1000); }); it('throws validation errors, if the file extension does not match', function () { @@ -177,8 +178,8 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertHasErrors(['file']); + ->set('file', $file) + ->assertHasErrors(['file']); }); it('throws validation errors, if the columns does not match', function () { @@ -210,9 +211,9 @@ 'requiredColumns' => $requiredColumns, 'columnLabels' => $columnLabels, ]) - ->set('file', $file) - ->call('import') - ->assertHasErrors(['columnsToMap.name', 'columnsToMap.email']); + ->set('file', $file) + ->call('import') + ->assertHasErrors(['columnsToMap.name', 'columnsToMap.email']); }); it('ensures the imports is batched', function () { @@ -229,16 +230,16 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'id' => 'id', - 'first_name' => 'first_name', - 'last_name' => 'last_name', - 'email' => 'email', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'id' => 'id', + 'first_name' => 'first_name', + 'last_name' => 'last_name', + 'email' => 'email', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); Bus::assertBatched(function (PendingBatch $batch) { return $batch->name == 'import-csv' && @@ -261,16 +262,16 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'id' => 'id', - 'first_name' => 'first_name', - 'last_name' => 'last_name', - 'email' => 'email', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'id' => 'id', + 'first_name' => 'first_name', + 'last_name' => 'last_name', + 'email' => 'email', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Customer::class); @@ -292,16 +293,16 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'id' => 'id', - 'first_name' => 'last_name', // This is intentional for this test - 'last_name' => 'first_name', // This is intentional for this test - 'email' => 'email', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'id' => 'id', + 'first_name' => 'last_name', // This is intentional for this test + 'last_name' => 'first_name', // This is intentional for this test + 'email' => 'email', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Customer::class); @@ -310,7 +311,7 @@ $this->assertEquals(Customer::count(), 1000); $this->assertEquals($import->first()->processed_rows, 1000); - $this->assertEquals(Customer::first()->first_name, "Ondricka"); + $this->assertEquals(Customer::first()->first_name, 'Ondricka'); }); it('can handled none required column even when column is empty', function () { @@ -325,16 +326,16 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'id' => '', // This is intentional for this test - 'first_name' => 'last_name', - 'last_name' => 'first_name', - 'email' => 'email', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'id' => '', // This is intentional for this test + 'first_name' => 'last_name', + 'last_name' => 'first_name', + 'email' => 'email', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Customer::class); @@ -343,7 +344,7 @@ $this->assertEquals(Customer::count(), 1000); $this->assertEquals($import->first()->processed_rows, 1000); - $this->assertEquals(Customer::first()->first_name, "Ondricka"); + $this->assertEquals(Customer::first()->first_name, 'Ondricka'); }); it('toggles import button', function () { @@ -352,7 +353,7 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->emit('toggle') - ->assertSet('open', true) - ->assertHasNoErrors(); + ->dispatch('toggle') + ->assertSet('open', true) + ->assertHasNoErrors(); }); diff --git a/tests/CsvUpsertTest.php b/tests/CsvUpsertTest.php index 0044c3d..af45aa0 100644 --- a/tests/CsvUpsertTest.php +++ b/tests/CsvUpsertTest.php @@ -7,6 +7,7 @@ use Askdkc\LivewireCsv\Tests\Models\User; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Config; + use function Pest\Livewire\livewire; beforeEach(fn () => $this->actingAs(User::factory()->create())); @@ -37,34 +38,34 @@ 'requiredColumns' => $requiredColumns, 'upsertColumns' => $upsertColumns, ]) - ->assertSet('model', $model) - ->assertSet('requiredColumns', [ - 'columnsToMap.title' => 'required', - 'columnsToMap.slug' => 'required', - 'columnsToMap.body' => 'required', - ]) - ->assertSet('upsertColumns', $upsertColumns); + ->assertSet('model', $model) + ->assertSet('requiredColumns', [ + 'columnsToMap.title' => 'required', + 'columnsToMap.slug' => 'required', + 'columnsToMap.body' => 'required', + ]) + ->assertSet('upsertColumns', $upsertColumns); }); it('returns csv headers & row counts when upload a file', function () { $file = UploadedFile::fake() - ->createWithContent( - 'posts.csv', - file_get_contents('stubs/posts.csv', true) - ); + ->createWithContent( + 'posts.csv', + file_get_contents('stubs/posts.csv', true) + ); $model = Post::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSet('fileHeaders', [ - 'title', 'slug', 'body', 'extra', - ]) - ->assertSet('fileRowCount', 2); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSet('fileHeaders', [ + 'title', 'slug', 'body', 'extra', + ]) + ->assertSet('fileRowCount', 2); }); it('creates posts records on top of csv file', function () { @@ -79,19 +80,19 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'title' => 'title', - 'slug' => 'slug', - 'body' => 'body', - 'extra' => 'extra', - ]) - ->set('upsertColumns', [ - 'slug', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'title' => 'title', + 'slug' => 'slug', + 'body' => 'body', + 'extra' => 'extra', + ]) + ->set('upsertColumns', [ + 'slug', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Post::class); @@ -113,19 +114,19 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'slug' => 'slug', - 'title' => 'body', // This is intentional for this test - 'body' => 'title', // This is intentional for this test - 'extra' => 'extra', - ]) - ->set('upsertColumns', [ - 'slug', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'slug' => 'slug', + 'title' => 'body', // This is intentional for this test + 'body' => 'title', // This is intentional for this test + 'extra' => 'extra', + ]) + ->set('upsertColumns', [ + 'slug', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Post::class); @@ -133,10 +134,9 @@ $this->assertEquals($import->count(), 1); $this->assertEquals(Post::count(), 2); - $this->assertEquals(Post::first()->title, "TestBody"); + $this->assertEquals(Post::first()->title, 'TestBody'); }); - it('creates tag records on top of csv file', function () { $file = UploadedFile::fake() ->createWithContent( @@ -149,18 +149,18 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'tag_id' => 'tag_id', - 'post_id' => 'post_id', - 'memo' => 'memo', - ]) - ->set('upsertColumns', [ - 'tag_id','post_id', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'tag_id' => 'tag_id', + 'post_id' => 'post_id', + 'memo' => 'memo', + ]) + ->set('upsertColumns', [ + 'tag_id', 'post_id', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Tag::class); @@ -170,7 +170,6 @@ $this->assertEquals($import->first()->processed_rows, 3); }); - it('updated tag records with csv succesfully', function () { $file = UploadedFile::fake() ->createWithContent( @@ -183,51 +182,50 @@ livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->set('columnsToMap', [ - 'tag_id' => 'tag_id', - 'post_id' => 'post_id', - 'memo' => 'sample', - ]) - ->set('upsertColumns', [ - 'tag_id','post_id', - ]) - ->call('import') - ->assertEmitted('imports.refresh') - ->assertHasNoErrors(); + ->set('file', $file) + ->set('columnsToMap', [ + 'tag_id' => 'tag_id', + 'post_id' => 'post_id', + 'memo' => 'sample', + ]) + ->set('upsertColumns', [ + 'tag_id', 'post_id', + ]) + ->call('import') + ->assertDispatched('imports.refresh') + ->assertHasNoErrors(); $import = Import::forModel(Tag::class); $this->assertEquals(Import::count(), 1); $this->assertEquals($import->count(), 1); $this->assertEquals(Tag::count(), 3); - $this->assertEquals(Tag::where('tag_id',1)->first()->memo, "sample1"); - $this->assertEquals(Tag::where('tag_id',2)->first()->memo, "sample2"); - $this->assertEquals(Tag::where('tag_id',3)->first()->memo, "sample3"); + $this->assertEquals(Tag::where('tag_id', 1)->first()->memo, 'sample1'); + $this->assertEquals(Tag::where('tag_id', 2)->first()->memo, 'sample2'); + $this->assertEquals(Tag::where('tag_id', 3)->first()->memo, 'sample3'); }); - it('read csv file as tsv', function () { Config::set('livewire_csv.file_type', 'tsv'); $file = UploadedFile::fake() - ->createWithContent( - 'posts.csv', - file_get_contents('stubs/posts.csv', true) - ); + ->createWithContent( + 'posts.csv', + file_get_contents('stubs/posts.csv', true) + ); $model = Post::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSet('fileHeaders', [ - 'title,"slug","body","extra"', - ]) - ->assertSet('fileRowCount', 2); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSet('fileHeaders', [ + 'title,"slug","body","extra"', + ]) + ->assertSet('fileRowCount', 2); }); it('read csv file as csv', function () { @@ -235,22 +233,22 @@ Config::set('livewire_csv.file_type', 'csv'); $file = UploadedFile::fake() - ->createWithContent( - 'posts.csv', - file_get_contents('stubs/posts.csv', true) - ); + ->createWithContent( + 'posts.csv', + file_get_contents('stubs/posts.csv', true) + ); $model = Post::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSet('fileHeaders', [ - 'title', 'slug', 'body', 'extra', - ]) - ->assertSet('fileRowCount', 2); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSet('fileHeaders', [ + 'title', 'slug', 'body', 'extra', + ]) + ->assertSet('fileRowCount', 2); }); it('return error when read csv file with semicolon delimiter', function () { @@ -258,25 +256,25 @@ Config::set('livewire_csv.file_type', 'csv'); $file = UploadedFile::fake() - ->createWithContent( - 'posts_semi.csv', - file_get_contents('stubs/posts_semi.csv', true) - ); + ->createWithContent( + 'posts_semi.csv', + file_get_contents('stubs/posts_semi.csv', true) + ); $model = Post::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertNotSet('fileHeaders', [ - 'title', 'slug', 'body', 'extra', - ]) - ->assertSet('fileHeaders', [ - 'title;"slug";"body";"extra"', - ]) - ->assertSet('fileRowCount', 2); + ->set('file', $file) + ->assertSet('model', $model) + ->assertNotSet('fileHeaders', [ + 'title', 'slug', 'body', 'extra', + ]) + ->assertSet('fileHeaders', [ + 'title;"slug";"body";"extra"', + ]) + ->assertSet('fileRowCount', 2); }); it('read csv file with semicolon delimiter without error', function () { @@ -284,20 +282,20 @@ Config::set('livewire_csv.set_delimiter', ';'); $file = UploadedFile::fake() - ->createWithContent( - 'posts_semi.csv', - file_get_contents('stubs/posts_semi.csv', true) - ); + ->createWithContent( + 'posts_semi.csv', + file_get_contents('stubs/posts_semi.csv', true) + ); $model = Post::class; livewire(CsvImporter::class, [ 'model' => $model, ]) - ->set('file', $file) - ->assertSet('model', $model) - ->assertSet('fileHeaders', [ - 'title', 'slug', 'body', 'extra', - ]) - ->assertSet('fileRowCount', 2); + ->set('file', $file) + ->assertSet('model', $model) + ->assertSet('fileHeaders', [ + 'title', 'slug', 'body', 'extra', + ]) + ->assertSet('fileRowCount', 2); }); diff --git a/tests/Database/Migrations/create_customers_table.php b/tests/Database/Migrations/create_customers_table.php index 5ff488f..8374209 100644 --- a/tests/Database/Migrations/create_customers_table.php +++ b/tests/Database/Migrations/create_customers_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration +return new class extends Migration { public function up() { diff --git a/tests/Database/Migrations/create_posts_table.php b/tests/Database/Migrations/create_posts_table.php index f58b42f..d5976cb 100644 --- a/tests/Database/Migrations/create_posts_table.php +++ b/tests/Database/Migrations/create_posts_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration +return new class extends Migration { public function up() { diff --git a/tests/Database/Migrations/create_tags_table.php b/tests/Database/Migrations/create_tags_table.php index 9701f2c..67be23b 100644 --- a/tests/Database/Migrations/create_tags_table.php +++ b/tests/Database/Migrations/create_tags_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration +return new class extends Migration { public function up() { diff --git a/tests/Database/Migrations/create_users_table.php b/tests/Database/Migrations/create_users_table.php index 57f0097..d52f72d 100644 --- a/tests/Database/Migrations/create_users_table.php +++ b/tests/Database/Migrations/create_users_table.php @@ -4,7 +4,7 @@ use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -return new class() extends Migration +return new class extends Migration { public function up() { diff --git a/tests/HandleImportsTest.php b/tests/HandleImportsTest.php index 81ea278..86f13f3 100644 --- a/tests/HandleImportsTest.php +++ b/tests/HandleImportsTest.php @@ -2,6 +2,7 @@ use Askdkc\LivewireCsv\Http\Livewire\HandleImports; use Askdkc\LivewireCsv\Tests\Models\User; + use function Pest\Livewire\livewire; it('renders handle imports component with model', function () { diff --git a/tests/Models/Tag.php b/tests/Models/Tag.php index 5ccef3e..ea46c78 100644 --- a/tests/Models/Tag.php +++ b/tests/Models/Tag.php @@ -10,5 +10,4 @@ class Tag extends Model use HasFactory; protected $guarded = []; - } diff --git a/tests/Models/User.php b/tests/Models/User.php index ed6b947..86305a9 100644 --- a/tests/Models/User.php +++ b/tests/Models/User.php @@ -8,8 +8,8 @@ class User extends \Illuminate\Foundation\Auth\User { - use HasFactory; use HasCsvImports; + use HasFactory; protected $guarded = []; diff --git a/tests/TestCase.php b/tests/TestCase.php index 2199080..c6b4e15 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -33,7 +33,7 @@ protected function setUp(): void rmdir(__DIR__.'/../vendor/orchestra/testbench-core/laravel/lang/ja'); } - if(is_file(__DIR__.'/../vendor/orchestra/testbench-core/laravel/configlivewire_csv.php')) { + if (is_file(__DIR__.'/../vendor/orchestra/testbench-core/laravel/configlivewire_csv.php')) { unlink(__DIR__.'/../vendor/orchestra/testbench-core/laravel/configlivewire_csv.php'); } } @@ -70,15 +70,18 @@ private function registerLivewireComponents(): self return $this; } - public function migrationExists(string $filename): Bool + public function migrationExists(string $filename): bool { $path = database_path('migrations/'); $files = scandir($path); $pos = false; foreach ($files as $value) { $pos = strpos($value, $filename); - if($pos !== false) return true; + if ($pos !== false) { + return true; + } } + return false; } }