Skip to content
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

Saving progress on standardized migration process/engine #539

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions newspack-custom-content-migrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,6 @@
Command\PublisherSpecific\CarsonNowMigrator::class,
Command\PublisherSpecific\ArkansasTimesMigrator::class,
Command\PublisherSpecific\ZocaloMigrator::class,
Command\PublisherSpecific\StandardMigrationTestMigrator::class,
)
);
109 changes: 109 additions & 0 deletions src/Command/PublisherSpecific/StandardMigrationTestMigrator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

namespace NewspackCustomContentMigrator\Command\PublisherSpecific;

use NewspackCustomContentMigrator\Command\InterfaceCommand;
use NewspackCustomContentMigrator\Migrator\AbstractMigrationRun;
use NewspackCustomContentMigrator\Migrator\JSONMigrationObjectsClass;
use NewspackCustomContentMigrator\Migrator\MigrationObjects;

class StandardMigrationTestMigrator implements InterfaceCommand {

private static $instance = null;

public static function get_instance() {
$class = get_called_class();
if ( null === self::$instance ) {
self::$instance = new $class();
}

return self::$instance;
}

/**
* @inheritDoc
*/
public function register_commands() {
\WP_CLI::add_command(
'newspack-content-migrator execute-user-migration',
[ $this, 'execute_user_migration' ],
[
'shortdesc' => 'Executes the user migration.',
'synopsis' => [
[
'type' => 'assoc',
'name' => 'path-to-json',
'description' => 'The JSON to migrate',
'optional' => false,
],
],
]
);
}

public function execute_user_migration( $args, $assoc_args ) {
( new class( $args, $assoc_args ) extends AbstractMigrationRun {

public function __construct( $args, $assoc_args ) {
$this->args = $args;
$this->assoc_args = $assoc_args;

$this->set_name( 'User Migration' );
}

/**
* Returns the migration objects.
*
* @return MigrationObjects
*/
public function get_migration_objects(): MigrationObjects {
return new JSONMigrationObjectsClass( $this->get_run_key(), $this->assoc_args['path-to-json'] );
}

/**
* This function houses the logic for the command.
*
* @param MigrationObjects $migration_objects The objects to perform the migration on.
*
* @return bool|\WP_Error
* @throws \Exception If an error occurs.
*/
public function command( MigrationObjects $migration_objects ): bool|\WP_Error {
foreach ( $migration_objects->get_unprocessed() as $migration_object ) {
$user_data = [
'user_pass' => wp_generate_password( 12 ),
];

if ( is_email( $migration_object->get()['user_login'] ) ) {
$user_data['user_login'] = substr( $migration_object->get()['user_login'], 0, strpos( $migration_object->get()['user_login'], '@' ) );
} else {
$user_data['user_login'] = $migration_object->get()['user_login'];
}

$user_data['user_email'] = $migration_object->get()['user_email'];

$user_data['display_name'] = $migration_object->get()['user_name'] . ' ' . $migration_object->get()['user_lastname'];

$user_data['user_nicename'] = sanitize_title( $user_data['display_name'] );

$user_id = wp_insert_user( $user_data );

if ( is_wp_error( $user_id ) ) {
\WP_CLI::error( 'Failed to insert user: ' . $user_id->get_error_message() );
return false;
} else {
\WP_CLI::success( 'Inserted user: ' . $user_data['user_login'] );
$migration_object->record_source( 'wp_users', 'user_login', $user_id, 'user_login' );
$migration_object->record_source( 'wp_users', 'user_email', $user_id, 'user_email' );
$migration_object->record_source( 'wp_users', 'display_name', $user_id, 'user_name' );
$migration_object->record_source( 'wp_users', 'display_name', $user_id, 'user_lastname' );
$migration_object->record_source( 'wp_users', 'user_nicename', $user_id, 'wp_users.display_name' );
$migration_object->store_processed_marker();
}
}

return true;
}
} )->start();
}
}
159 changes: 159 additions & 0 deletions src/Migrator/AbstractMigrationObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
<?php

namespace NewspackCustomContentMigrator\Migrator;

use NewspackCustomContentMigrator\Migrator\MigrationObject;

abstract class AbstractMigrationObject implements MigrationObject {

protected MigrationRunKey $run_key;

protected object|array $data;

protected string $pointer_to_identifier;

protected bool $processed;

private \wpdb $wpdb;

public function __construct( MigrationRunKey $run_key ) {
$this->run_key = $run_key;
global $wpdb;
$this->wpdb = $wpdb;
}

/**
* @inheritDoc
*/
public function set_run_key( MigrationRunKey $run_key ): void {
// TODO: Implement set_run_key() method.
}

/**
* @inheritDoc
*/
public function get_run_key(): MigrationRunKey {
return $this->run_key;
}

/**
* @inheritDoc
*/
public function set( object|array $data, string $pointer_to_identifier = 'id' ): void {
$this->data = $data;
$this->pointer_to_identifier = $pointer_to_identifier;
// TODO setting of $processed could be improved by using a cache
$this->has_been_processed();
}

/**
* @inheritDoc
*/
public function get(): array|object {
return $this->data;
}

/**
* @return string
*/
public function get_pointer_to_identifier(): string {
return $this->pointer_to_identifier;
}

/**
* @inheritDoc
*/
public function store(): bool {
$insert = $this->wpdb->insert(
$this->wpdb->options,
[
'option_name' => $this->get_run_key()->get() . '_migration_object_' . $this->get() [ $this->get_pointer_to_identifier() ],
'option_value' => wp_json_encode( $this->get() ),
'autoload' => 'no',
]
);

if ( ! is_bool( $insert ) ) {
return false;
}

return $insert;
}

/**
* @inheritDoc
*/
public function store_processed_marker(): bool {
$insert = $this->wpdb->insert(
$this->wpdb->options,
[
'option_name' => $this->get_run_key()->get() . '_migration_object_' . $this->get()[ $this->get_pointer_to_identifier() ] . '_processed',
'option_value' => '1',
'autoload' => 'no',
]
);

if ( ! is_bool( $insert ) ) {
return false;
}

if ( $insert ) {
$this->processed = true;
}

return $insert;
}

/**
* @inheritDoc
*/
public function has_been_processed(): bool {
if ( ! isset( $this->processed ) ) {
// phpcs:disable
$options_table = $this->wpdb->options;
$this->processed = (bool) $this->wpdb->get_var(
$this->wpdb->prepare(
"SELECT option_value FROM {$options_table} WHERE option_name = %s",
$this->get_run_key()->get() . '_migration_object_' . $this->get()[ $this->get_pointer_to_identifier() ] . '_processed'
)
);
// phpcs:enable
}

return $this->processed;
}

/**
* @inheritDoc
*/
public function record_source( string $table, string $column, int $id, string $source ): bool {
$meta_table = match ( $table ) {
'wp_users' => $this->wpdb->usermeta,
'wp_posts' => $this->wpdb->postmeta,
'wp_terms' => $this->wpdb->termmeta,
default => $this->wpdb->options,
};

$option_name = $this->get_run_key()->get() . '_migration_object_source_' . $this->get()[ $this->get_pointer_to_identifier() ] . "_{$table}_{$column}_{$id}";
$insert = $this->wpdb->insert(
$meta_table,
[
'meta_key' => $option_name,
'meta_value' => wp_json_encode(
[
'table' => $table,
'column' => $column,
'id' => $id,
'source' => $source,
]
),
]
);

if ( ! is_bool( $insert ) ) {
return false;
}

return $insert;
}
}
57 changes: 57 additions & 0 deletions src/Migrator/AbstractMigrationObjects.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace NewspackCustomContentMigrator\Migrator;

use NewspackCustomContentMigrator\Migrator\MigrationObjects;

abstract class AbstractMigrationObjects implements MigrationObjects {

private MigrationRunKey $run_key;

protected iterable $data;

public function __construct( iterable $data, MigrationRunKey $run_key ) {
$this->data = $data;
$this->run_key = $run_key;
}

/**
* @inheritDoc
*/
public function set_run_key( MigrationRunKey $run_key ): void {
$this->run_key = $run_key;
}

/**
* @inheritDoc
*/
public function get_run_key(): MigrationRunKey {
return $this->run_key;
}

/**
* Returns all processed migration objects.
*
* @return MigrationObject[]
*/
public function get_processed(): iterable {
foreach ( $this->get_all() as $migration_object ) {
if ( $migration_object->has_been_processed() ) {
yield $migration_object;
}
}
}

/**
* Returns all unprocessed migration objects.
*
* @return MigrationObject[]
*/
public function get_unprocessed(): iterable {
foreach ( $this->get_all() as $migration_object ) {
if ( ! $migration_object->has_been_processed() ) {
yield $migration_object;
}
}
}
}
Loading