Skip to content

wip #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Draft

wip #16

Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"autoload": {
"psr-4": {
"Migrator\\": "src/"
}
}
}
18 changes: 18 additions & 0 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions legacy/config.example.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<?php
const ACCESS_TOKEN = 'shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
const SHOPIFY_DOMAIN = 'your-store.myshopify.com';
File renamed without changes.
13 changes: 13 additions & 0 deletions plugin.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php
/**
* Plugin Name: Migrator
* Version: 0.1.0
*
* @package Migrator
*/

require_once __DIR__ . '/vendor/autoload.php';

add_action( 'plugins_loaded', function () {
( new Migrator\Main )->init();
} );
63 changes: 63 additions & 0 deletions src/CLI.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Migrator;

use WP_CLI;
use WP_CLI_Command;

class CLI extends WP_CLI_Command {
/**
* ## OPTIONS
*
* [--dry-run]
* : Run the command without actually doing anything
*
* [--before]
* : Query Order before this date. ISO 8601 format.
*
* [--after]
* : Query Order after this date. ISO 8601 format.
*
* [--limit]
* : Limit the total number of orders to process.
*
* [--perpage]
* : Limit the number of orders to process each time.
*
* [--status]
* : Product status.
*
* [--ids]
* : Query products by IDs.
*
* [--exclude]
* : Exclude products by IDs or by SKU pattern.
*
* [--handle]
* : Query products by handles
*
* [--product-type]
* : single or variable or all.
*
* [--fields]
* : Only migrate/update selected fields.
*
* [--exclude-fields]
* : Exclude selected fields from update.
*
* [--remove-orphans]
* : Remove orphans order items
*
* [--source]
* : Source ID.
*
* @when after_wp_load
*/
public function products( $args, $assoc_args ) {
$migrator = Main::container()->get(
Migrators\Product::class,
[ 'source' => $assoc_args['source'] ]
);
$migrator->run( $assoc_args );
}
}
13 changes: 13 additions & 0 deletions src/Interfaces/Source.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Migrator\Interfaces;

interface Source {
const IDENTIFIER = '';

const CREDENTIALS = [];

public function get_products();

public function get_orders();
}
61 changes: 61 additions & 0 deletions src/Main.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php
namespace Migrator;

use Migrator\Migrators\Product;
use Migrator\Registry\Container;

class Main {

public function init() {
if ( ! class_exists( 'WooCommerce', false ) ) {
return;
}

$this->register_dependencies();

add_action( 'cli_init', function() {
\WP_CLI::add_command( 'migrator', 'Migrator\\CLI' );
} );
}

private function register_dependencies() {
$container = self::container( true );

// Passing a container instance to the Sources class to manage sources.
$container->register( Sources::class, function() {
return new Sources( new Container() );
} );

$container->register( Workers::class, function() {
return new Workers();
} );

$container->register(
Migrators\Product::class,
$container->factory( function( Container $container, $parameters ) {
return new Product(
$container->get( Sources::class )->get_source( $parameters ),
$container->get( Workers::class )->get_workers( 'product' )
);
} )
);
}

/**
* Loads the dependency injection container.
*
* @param boolean $reset Used to reset the container to a fresh instance.
* Note: this means all dependencies will be
* reconstructed.
*/
public static function container( $reset = false ) {
static $container;
if (
! $container instanceof Container
|| $reset
) {
$container = new Container();
}
return $container;
}
}
103 changes: 103 additions & 0 deletions src/Migrators/Product.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace Migrator\Migrators;

use Migrator\Interfaces\Source;

final class Product {

const IDENTIFIER = 'product';

private $args;

private $source;

private $workers;

public function __construct( Source $source, array $workers) {
$this->source = $source;
$this->workers = $workers;
}

public function run( $args = [] ) {
$this->args = $args;

array_map(
function( $original_product ) {
$this->migrate( $original_product );
},
$this->source->get_products()
);
}

private function migrate( $original_product ) {
$product = $this->get_existing( $original_product );

if ( ! $product && $this->is_sync() ) {
return;
}

if ( ! $product ) {
$product = new \WC_Product();
$product->update_meta_data( '_original_product_id', $original_product['id'] );
$product->save();
}

// Processing the product data.
foreach( $this->workers as $identifier => $worker ) {
try {
call_user_func( $worker, $product, $original_product );
} catch ( \Exception $e ) {
// Log the error.
}
}

$product->save();
}

private function is_sync() {
return isset( $this->args['sync'] ) && $this->args['sync'];
}

private function get_existing( $original_product ) {
$id = $original_product['id'] ?? 0;
$sku = $original_product['sku'] ?? '';
$slug = $original_product['slug'] ?? '' ;

// Try finding the product by original product ID.
if ( $id ) {
$woo_products = wc_get_products(
array(
'limit' => 1,
'meta_key' => '_original_product_id',
'meta_value' => $id,
)
);

if ( count( $woo_products ) === 1 && is_a( $woo_products[0], 'WC_Product' ) ) {
return wc_get_product( $woo_products[0] );
}
}

// Check if the product already exists in Woo by SKU. Only if the
// product is a single product.
if ( $sku ) {
$woo_product = wc_get_product_id_by_sku( $sku );

if ( $woo_product ) {
return wc_get_product( $woo_product );
}
}

// Check if the product already exists in Woo by slug.
if ( $slug ) {
$woo_product = get_page_by_path( $slug, OBJECT, 'product' );

if ( $woo_product ) {
return wc_get_product( $woo_product );
}
}

return null;
}
}
56 changes: 56 additions & 0 deletions src/Registry/AbstractDependencyType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php
namespace Migrator\Registry;

/**
* An abstract class for dependency types.
*
* Dependency types are instances of a dependency used by the
* Dependency Injection Container for storing dependencies to invoke as they
* are needed.
*
* @since 2.5.0
*/
abstract class AbstractDependencyType {

/**
* Holds a callable or value provided for this type.
*
* @var mixed
*/
private $callable_or_value;

/**
* Constructor
*
* @param mixed $callable_or_value A callable or value for the dependency
* type instance.
*/
public function __construct( $callable_or_value ) {
$this->callable_or_value = $callable_or_value;
}

/**
* Resolver for the internal dependency value.
*
* @param Container $container The Dependency Injection Container.
* @param array $parameters The parameters to pass to the callback.
*
* @return mixed
*/
protected function resolve_value( Container $container, $parameters ) {
$callback = $this->callable_or_value;
return \is_callable( $callback )
? $callback( $container, $parameters )
: $callback;
}

/**
* Retrieves the value stored internally for this DependencyType
*
* @param Container $container The Dependency Injection Container.
* @param array $parameters The parameters to pass to the callback.
*
* @return void
*/
abstract public function get( Container $container, $parameters );
}
Loading