Skip to content

Commit

Permalink
Product import command & add utility to start imports (#46)
Browse files Browse the repository at this point in the history
  • Loading branch information
FinnPaes authored Dec 12, 2023
1 parent bbe9b97 commit 57bd016
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 58 deletions.
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,9 @@ By default you'll get the configured content on categories and products availabl
- Product: `resources/views/vendor/rapidez/product/overview.blade.php`
- Category: `resources/views/vendor/rapidez/category/overview.blade.php`

### Importing categories from Magento
### Importing categories or products from Magento

#### Categories

To make it easier to change category content in bulk you can create category entries with content copied over in bulk.

Expand All @@ -123,6 +125,32 @@ Event::listen('rapidez-statamic:category-entry-data', fn($category) => [
]
);
```

#### Products

To make it easier to change product content in bulk you can create product entries with content copied over in bulk.

To do this run one of the following:

```bash
# Most basic, import all products in all sites
php artisan rapidez:statamic:import:products

# Import all products in the site with handle "default" only
php artisan rapidez:statamic:import:products --site=default
```

By default the slug and title of the product are copied.

If you have a custom blueprint and would like to add more data from the product you can do so by hooking into the `rapidez-statamic:product-entry-data` event:

```php
Event::listen('rapidez-statamic:product-entry-data', fn($product) => [
'description' => $product->description,
]
);
```

### Forms

When you create a form you could use `rapidez-statamic::emails.form` as HTML template which uses the [Laravel mail template](https://laravel.com/docs/master/mail#customizing-the-components) with all fields in a table, make sure you enable markdown!
Expand Down
12 changes: 12 additions & 0 deletions config/rapidez-statamic.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
'category' => true,
],

// Which collection and blueprint should be used for importing products?
'import' => [
'categories' => [
'collection' => 'categories',
'blueprint' => 'category',
],
'products' => [
'collection' => 'products',
'blueprint' => 'product',
],
],

'runway' => [
// Should we configure Runway? You'll get a products,
// categories and brands / manufacturers resource.
Expand Down
35 changes: 35 additions & 0 deletions resources/views/utilities/import_utility/imports.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@extends('statamic::layout')
@section('title', __('Import'))

@section('content')
<div class="flex items-center justify-between">
<h1>{{ __('Import categories') }}</h1>
</div>

<div class="mt-3 card">
<form action="{{ cp_route('utilities.imports.import-categories') }}" method="POST">
@csrf

<p class="mb-2">@lang('The import of non-existing categories may be started through the button below.')</p>

<div class="flex items-center space-x-3">
<button type="submit" class="btn-primary">@lang("Import categories")</button>
</div>
</form>
</div>

<div class="flex items-center justify-between mt-5">
<h1>{{ __('Import products') }}</h1>
</div>

<div class="mt-3 card">
<form action="{{ cp_route('utilities.imports.import-products') }}" method="POST">
@csrf

<p class="mb-2">@lang('The import of non-existing products may be started through the button below.')</p>
<div class="flex items-center space-x-3">
<button type="submit" class="btn-primary">@lang("Import products")</button>
</div>
</form>
</div>
@stop
41 changes: 41 additions & 0 deletions src/Actions/StatamicEntryAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Rapidez\Statamic\Actions;

use Statamic\Facades\Entry;
use ReflectionClass;

class StatamicEntryAction
{
public static function createEntry(array $attributes, array $values = []): void
{
if (Entry::query()->where($attributes)->count()) {
// Entry was already created.
return;
}

/** @var \Statamic\Entries\Entry $entry */
$entry = Entry::make();
$values = array_merge($attributes, $values);

static::setEntryData($entry, $values)->save();
}

public static function setEntryData(\Statamic\Entries\Entry $entry, array $values = []) : \Statamic\Entries\Entry
{
$reflectedEntry = new ReflectionClass($entry);
foreach ($values as $key => $value) {
// Check if the key is a statamic setter
if (!$reflectedEntry->hasMethod($key) || $reflectedEntry->getMethod($key)->getNumberOfParameters() < 1) {
continue;
}

$entry->$key($value);
unset($values[$key]);
}

$entry->merge($values);

return $entry;
}
}
58 changes: 13 additions & 45 deletions src/Commands/ImportCategories.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@

namespace Rapidez\Statamic\Commands;

use Statamic\Facades\Site;
use Illuminate\Console\Command;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Str;
use Rapidez\Core\Facades\Rapidez;
use Rapidez\Statamic\Jobs\ImportCategoriesJob;
use ReflectionClass;
use Statamic\Facades\Entry;
use Statamic\Facades\Site;
use Symfony\Component\Console\Helper\ProgressBar;
use Illuminate\Support\Facades\Event;
use Rapidez\Statamic\Actions\StatamicEntryAction;

class ImportCategories extends Command
{
Expand All @@ -24,6 +19,9 @@ public function handle(): int
$categoryModel = config('rapidez.models.category');
$categoryModelInstance = new $categoryModel;

/** @var StatamicEntryAction $statamicEntryAction */
$statamicEntryAction = app(StatamicEntryAction::class);

$categoryIdentifiers = $this->argument('categories');
if (!$categoryIdentifiers && !$this->option('all')) {
$this->error(__('You must enter categories or pass the --all flag.'));
Expand Down Expand Up @@ -60,54 +58,24 @@ public function handle(): int
->lazy();

foreach ($categories as $category) {
static::createEntry(
$statamicEntryAction::createEntry(
[
'collection' => 'categories',
'blueprint' => 'category',
'collection' => config('rapidez-statamic.import.categories.collection', 'categories'),
'blueprint' => config('rapidez-statamic.import.categories.blueprint', 'category'),
'site' => $site->handle(),
'linked_category' => $category->entity_id,
],
array_merge(...Event::dispatch('rapidez-statamic:category-entry-data', ['category' => $category]))
array_merge([
'locale' => $site->handle(),
'site' => $site->handle(),
], ...Event::dispatch('rapidez-statamic:category-entry-data', ['category' => $category]))
);
}

$bar->advance();
}
$bar->finish();


return static::SUCCESS;
}

protected static function createEntry(array $attributes, array $values = [])
{
if (Entry::query()->where($attributes)->count()) {
// Entry was already created.
return;
}

/** @var \Statamic\Entries\Entry $entry */
$entry = Entry::make();
$values = array_merge($attributes, $values);

static::setEntryData($entry, $values)->save();
}

protected static function setEntryData(\Statamic\Entries\Entry $entry, array $values = []) : \Statamic\Entries\Entry
{
$reflectedEntry = new ReflectionClass($entry);
foreach ($values as $key => $value) {
// Check if the key is a statamic setter
if (!$reflectedEntry->hasMethod($key) || $reflectedEntry->getMethod($key)->getNumberOfParameters() < 1) {
continue;
}

$entry->$key($value);
unset($values[$key]);
}

$entry->merge($values);

return $entry;
}
}
66 changes: 66 additions & 0 deletions src/Commands/ImportProducts.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace Rapidez\Statamic\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Event;
use Rapidez\Core\Facades\Rapidez;
use Rapidez\Statamic\Actions\StatamicEntryAction;
use Statamic\Facades\Site;

class ImportProducts extends Command
{
protected $signature = 'rapidez:statamic:import:products {--site=* : Sites handles or urls to process, if none are passed it will be done for all sites (Default will be all sites)}';

protected $description = 'Create a new product entry for a product if it does not exist.';

public function handle()
{
$productModel = config('rapidez.models.product');

/** @var StatamicEntryAction $statamicEntryAction */
$statamicEntryAction = app(StatamicEntryAction::class);

$sites = $this->option('site');
$sites = $sites
? array_filter(array_map(fn($handle) => (Site::get($handle) ?: Site::findByUrl($handle)) ?: $this->output->warning(__('No site found with handle or url: :handle', ['handle' => $handle])), $sites))
: Site::all();

$bar = $this->output->createProgressBar(count($sites));
$bar->start();
foreach($sites as $site) {
$bar->display();

$siteAttributes = $site->attributes();
if (!isset($siteAttributes['magento_store_id'])) {
continue;
}

Rapidez::setStore($siteAttributes['magento_store_id']);

$products = $productModel::query()
->selectAttributes(['entity_id', 'sku', 'name', 'url_key'])
->lazy();

foreach ($products as $product) {
$statamicEntryAction::createEntry(
[
'collection' => config('rapidez-statamic.import.products.collection', 'products'),
'blueprint' => config('rapidez-statamic.import.products.blueprint', 'product'),
'site' => $site->handle(),
'linked_product' => $product->sku,
],
array_merge([
'locale' => $site->handle(),
'site' => $site->handle(),
], ...Event::dispatch('rapidez-statamic:product-entry-data', ['product' => $product]))
);
}

$bar->advance();
}
$bar->finish();

return static::SUCCESS;
}
}
37 changes: 37 additions & 0 deletions src/Http/Controllers/ImportsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Rapidez\Statamic\Http\Controllers;

use Statamic\Facades\CP\Toast;
use Illuminate\Contracts\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Artisan;
use Statamic\Http\Controllers\Controller;

class ImportsController extends Controller
{
public function __invoke() : View
{
return view('rapidez-statamic::utilities.import_utility.imports');
}

public function importCategories() : RedirectResponse
{
Artisan::queue('rapidez:statamic:import:categories --all')
->onQueue('imports');

Toast::success(__('The import of categories has started!'))->duration(5000);

return redirect(cp_route('utilities.imports'));
}

public function importProducts() : RedirectResponse
{
Artisan::queue('rapidez:statamic:import:products')
->onQueue('imports');

Toast::success(__('The import of products has started!'))->duration(5000);

return redirect(cp_route('utilities.imports'));
}
}
Loading

0 comments on commit 57bd016

Please sign in to comment.