From 57bd016fdceb2e6cb79c5ff66d541be208c15a74 Mon Sep 17 00:00:00 2001
From: Finn <71390226+FinnPaes@users.noreply.github.com>
Date: Tue, 12 Dec 2023 11:59:16 +0100
Subject: [PATCH] Product import command & add utility to start imports (#46)
---
README.md | 30 ++++++++-
config/rapidez-statamic.php | 12 ++++
.../import_utility/imports.blade.php | 35 ++++++++++
src/Actions/StatamicEntryAction.php | 41 ++++++++++++
src/Commands/ImportCategories.php | 58 ++++------------
src/Commands/ImportProducts.php | 66 +++++++++++++++++++
src/Http/Controllers/ImportsController.php | 37 +++++++++++
src/RapidezStatamicServiceProvider.php | 56 ++++++++++++----
8 files changed, 277 insertions(+), 58 deletions(-)
create mode 100644 resources/views/utilities/import_utility/imports.blade.php
create mode 100644 src/Actions/StatamicEntryAction.php
create mode 100644 src/Commands/ImportProducts.php
create mode 100644 src/Http/Controllers/ImportsController.php
diff --git a/README.md b/README.md
index 564bcb7..5bab231 100644
--- a/README.md
+++ b/README.md
@@ -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.
@@ -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!
diff --git a/config/rapidez-statamic.php b/config/rapidez-statamic.php
index ab51539..d1de45a 100644
--- a/config/rapidez-statamic.php
+++ b/config/rapidez-statamic.php
@@ -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.
diff --git a/resources/views/utilities/import_utility/imports.blade.php b/resources/views/utilities/import_utility/imports.blade.php
new file mode 100644
index 0000000..364060e
--- /dev/null
+++ b/resources/views/utilities/import_utility/imports.blade.php
@@ -0,0 +1,35 @@
+@extends('statamic::layout')
+@section('title', __('Import'))
+
+@section('content')
+
+
{{ __('Import categories') }}
+
+
+
+
+
+
{{ __('Import products') }}
+
+
+
+@stop
\ No newline at end of file
diff --git a/src/Actions/StatamicEntryAction.php b/src/Actions/StatamicEntryAction.php
new file mode 100644
index 0000000..e4ac214
--- /dev/null
+++ b/src/Actions/StatamicEntryAction.php
@@ -0,0 +1,41 @@
+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;
+ }
+}
diff --git a/src/Commands/ImportCategories.php b/src/Commands/ImportCategories.php
index 1d13c20..c43dd6c 100644
--- a/src/Commands/ImportCategories.php
+++ b/src/Commands/ImportCategories.php
@@ -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
{
@@ -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.'));
@@ -60,14 +58,17 @@ 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]))
);
}
@@ -75,39 +76,6 @@ public function handle(): int
}
$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;
- }
}
diff --git a/src/Commands/ImportProducts.php b/src/Commands/ImportProducts.php
new file mode 100644
index 0000000..bdb4302
--- /dev/null
+++ b/src/Commands/ImportProducts.php
@@ -0,0 +1,66 @@
+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;
+ }
+}
diff --git a/src/Http/Controllers/ImportsController.php b/src/Http/Controllers/ImportsController.php
new file mode 100644
index 0000000..320c916
--- /dev/null
+++ b/src/Http/Controllers/ImportsController.php
@@ -0,0 +1,37 @@
+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'));
+ }
+}
diff --git a/src/RapidezStatamicServiceProvider.php b/src/RapidezStatamicServiceProvider.php
index 22e7518..24fe71d 100644
--- a/src/RapidezStatamicServiceProvider.php
+++ b/src/RapidezStatamicServiceProvider.php
@@ -2,25 +2,29 @@
namespace Rapidez\Statamic;
+use Statamic\Statamic;
+use Statamic\Sites\Sites;
+use Statamic\Facades\Site;
+use Statamic\Facades\Entry;
+use Statamic\Facades\Utility;
+use Illuminate\Routing\Router;
+use Rapidez\Core\Facades\Rapidez;
+use Statamic\Events\GlobalSetSaved;
+use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
-use Illuminate\Support\Facades\View;
+use Rapidez\Statamic\Tags\Alternates;
+use Statamic\Events\GlobalSetDeleted;
use Illuminate\Support\ServiceProvider;
use Illuminate\View\View as RenderedView;
-use Rapidez\Core\Facades\Rapidez;
+use Rapidez\Statamic\Forms\JsDrivers\Vue;
+use Rapidez\Statamic\Commands\ImportProducts;
use Rapidez\Statamic\Commands\ImportCategories;
use Rapidez\Statamic\Extend\SitesLinkedToMagentoStores;
-use Rapidez\Statamic\Forms\JsDrivers\Vue;
+use Rapidez\Statamic\Http\Controllers\ImportsController;
use Rapidez\Statamic\Http\Controllers\StatamicRewriteController;
use Rapidez\Statamic\Http\ViewComposers\StatamicGlobalDataComposer;
-use Rapidez\Statamic\Tags\Alternates;
-use Statamic\Events\GlobalSetDeleted;
-use Statamic\Events\GlobalSetSaved;
-use Statamic\Facades\Entry;
-use Statamic\Facades\Site;
-use Statamic\Sites\Sites;
-use Statamic\Statamic;
class RapidezStatamicServiceProvider extends ServiceProvider
{
@@ -41,7 +45,8 @@ public function boot()
->bootListeners()
->bootRunway()
->bootComposers()
- ->bootPublishables();
+ ->bootPublishables()
+ ->bootUtilities();
Vue::register();
Alternates::register();
@@ -50,7 +55,8 @@ public function boot()
public function bootCommands() : self
{
$this->commands([
- ImportCategories::class
+ ImportCategories::class,
+ ImportProducts::class,
]);
return $this;
@@ -90,6 +96,11 @@ public function bootListeners() : self
'title' => $category->name,
'slug' => trim($category->url_key),
]);
+
+ Event::listen('rapidez-statamic:product-entry-data', fn($product) => [
+ 'title' => $product->name,
+ 'slug' => trim($product->url_key),
+ ]);
}
return $this;
@@ -161,6 +172,27 @@ public function bootPublishables() : self
return $this;
}
+ public function bootUtilities() : static
+ {
+ Utility::extend(function () : void {
+ Utility::register('imports')
+ ->icon('synchronize')
+ ->action(ImportsController::class)
+ ->title(__('Import'))
+ ->navTitle(__('Import'))
+ ->description(__('Import products or categories from Magento'))
+ ->routes(function (Router $router) : void {
+ $router->post('/import-categories', [ImportsController::class, 'importCategories'])
+ ->name('import-categories');
+
+ $router->post('/import-products', [ImportsController::class, 'importProducts'])
+ ->name('import-products');
+ });
+ });
+
+ return $this;
+ }
+
public function currentSiteIsEnabled(): bool
{
return !config('statamic.sites.sites.' . Site::current()->handle() . '.attributes.disabled', false);