first commit
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Variables\Services\Batch_Operations;
|
||||
|
||||
use Exception;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\DuplicatedLabel;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\RecordNotFound;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\VariablesLimitReached;
|
||||
|
||||
class Batch_Error_Formatter {
|
||||
|
||||
private const ERROR_MAP = [
|
||||
RecordNotFound::class => [
|
||||
'code' => 'variable_not_found',
|
||||
'status' => 404,
|
||||
],
|
||||
DuplicatedLabel::class => [
|
||||
'code' => 'duplicated_label',
|
||||
'status' => 400,
|
||||
],
|
||||
VariablesLimitReached::class => [
|
||||
'code' => 'invalid_variable_limit_reached',
|
||||
'status' => 400,
|
||||
],
|
||||
];
|
||||
|
||||
public function status_for( Exception $e ): int {
|
||||
foreach ( self::ERROR_MAP as $class => $map ) {
|
||||
if ( $e instanceof $class ) {
|
||||
return $map['status'];
|
||||
}
|
||||
}
|
||||
|
||||
return 500;
|
||||
}
|
||||
|
||||
public function error_code_for( Exception $e ): string {
|
||||
foreach ( self::ERROR_MAP as $class => $map ) {
|
||||
if ( $e instanceof $class ) {
|
||||
return $map['code'];
|
||||
}
|
||||
}
|
||||
|
||||
return 'unexpected_server_error';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Variables\Services\Batch_Operations;
|
||||
|
||||
use Elementor\Modules\Variables\Storage\Entities\Variable;
|
||||
use Elementor\Modules\Variables\Storage\Variables_Collection;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\BatchOperationFailed;
|
||||
|
||||
class Batch_Processor {
|
||||
private const OPERATION_MAP = [
|
||||
'create' => 'op_create',
|
||||
'update' => 'op_update',
|
||||
'delete' => 'op_delete',
|
||||
'restore' => 'op_restore',
|
||||
];
|
||||
|
||||
/**
|
||||
* @throws BatchOperationFailed Invalid operation type.
|
||||
*/
|
||||
public function apply_operation( Variables_Collection $collection, array $operation ): array {
|
||||
$type = $operation['type'];
|
||||
|
||||
if ( ! isset( self::OPERATION_MAP[ $type ] ) ) {
|
||||
throw new BatchOperationFailed( 'Invalid operation type: ' . esc_html( $type ), [] );
|
||||
}
|
||||
|
||||
$method = self::OPERATION_MAP[ $type ];
|
||||
|
||||
return $this->$method( $collection, $operation );
|
||||
}
|
||||
|
||||
private function op_create( Variables_Collection $collection, array $operation ): array {
|
||||
$data = $operation['variable'];
|
||||
$temp_id = $data['id'] ?? null;
|
||||
$data['id'] = $collection->next_id();
|
||||
|
||||
$collection->assert_limit_not_reached();
|
||||
$collection->assert_label_is_unique( $data['label'] );
|
||||
|
||||
if ( ! isset( $data['order'] ) ) {
|
||||
$data['order'] = $collection->get_next_order();
|
||||
}
|
||||
|
||||
$variable = Variable::create_new( $data );
|
||||
|
||||
$collection->add_variable( $variable );
|
||||
|
||||
// TODO: do we need to return all this payload maybe return what the clients want
|
||||
return [
|
||||
'type' => 'create',
|
||||
'id' => $data['id'],
|
||||
'temp_id' => $temp_id,
|
||||
'variable' => $variable->to_array(),
|
||||
];
|
||||
}
|
||||
|
||||
private function op_update( Variables_Collection $collection, array $operation ): array {
|
||||
$id = $operation['id'];
|
||||
$data = $operation['variable'];
|
||||
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
if ( isset( $data['label'] ) ) {
|
||||
$collection->assert_label_is_unique( $data['label'], $id );
|
||||
}
|
||||
|
||||
$variable->apply_changes( $data );
|
||||
|
||||
return [
|
||||
'type' => 'update',
|
||||
'id' => $id,
|
||||
'variable' => $variable->to_array(),
|
||||
];
|
||||
}
|
||||
|
||||
private function op_delete( Variables_Collection $collection, array $operation ): array {
|
||||
$id = $operation['id'];
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
$variable->soft_delete();
|
||||
|
||||
return [
|
||||
'type' => 'delete',
|
||||
'id' => $id,
|
||||
'deleted' => true,
|
||||
];
|
||||
}
|
||||
|
||||
private function op_restore( Variables_Collection $collection, array $operation ): array {
|
||||
$id = $operation['id'];
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
$collection->assert_limit_not_reached();
|
||||
|
||||
if ( isset( $operation['label'] ) ) {
|
||||
$collection->assert_label_is_unique( $operation['label'], $id );
|
||||
}
|
||||
|
||||
$variable->apply_changes( $operation );
|
||||
|
||||
$variable->restore();
|
||||
|
||||
return [
|
||||
'type' => 'restore',
|
||||
'id' => $id,
|
||||
'variable' => $variable->to_array(),
|
||||
];
|
||||
}
|
||||
|
||||
public function operation_id( array $operation, int $index ): string {
|
||||
if ( 'create' === $operation['type'] && isset( $operation['variable']['id'] ) ) {
|
||||
return $operation['variable']['id'];
|
||||
}
|
||||
|
||||
if ( isset( $operation['id'] ) ) {
|
||||
return $operation['id'];
|
||||
}
|
||||
|
||||
return "operation_{$index}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
namespace Elementor\Modules\Variables\Services;
|
||||
|
||||
use Elementor\Modules\Variables\Services\Batch_Operations\Batch_Error_Formatter;
|
||||
use Elementor\Modules\Variables\Services\Batch_Operations\Batch_Processor;
|
||||
use Elementor\Modules\Variables\Storage\Entities\Variable;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\BatchOperationFailed;
|
||||
use Elementor\Modules\Variables\Storage\Variables_Repository;
|
||||
use Elementor\Modules\Variables\Storage\Exceptions\FatalError;
|
||||
use Elementor\Modules\Variables\PropTypes\Size_Variable_Prop_Type;
|
||||
use Elementor\Utils as ElementorUtils;
|
||||
|
||||
class Variables_Service {
|
||||
private Variables_Repository $repo;
|
||||
private Batch_Processor $batch_processor;
|
||||
|
||||
public function __construct( Variables_Repository $repository, Batch_Processor $batch_processor ) {
|
||||
$this->repo = $repository;
|
||||
$this->batch_processor = $batch_processor;
|
||||
}
|
||||
|
||||
public function get_variables_list(): array {
|
||||
return $this->load()['data'];
|
||||
}
|
||||
|
||||
public function load() {
|
||||
$collection = $this->repo->load()->serialize( true );
|
||||
foreach ( $collection['data'] as $id => $variable ) {
|
||||
if ( ! ElementorUtils::has_pro() && Size_Variable_Prop_Type::get_key() === $variable['type'] ) {
|
||||
unset( $collection['data'][ $id ] );
|
||||
}
|
||||
}
|
||||
return $collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws BatchOperationFailed Thrown when one of the operations fails.
|
||||
* @throws FatalError Failed to save after batch.
|
||||
*/
|
||||
public function process_batch( array $operations ) {
|
||||
$collection = $this->repo->load();
|
||||
$results = [];
|
||||
$errors = [];
|
||||
|
||||
$error_formatter = new Batch_Error_Formatter();
|
||||
|
||||
foreach ( $operations as $index => $operation ) {
|
||||
try {
|
||||
$results[] = $this->batch_processor->apply_operation( $collection, $operation );
|
||||
|
||||
} catch ( \Exception $e ) {
|
||||
$errors[ $this->batch_processor->operation_id( $operation, $index ) ] = [
|
||||
'status' => $error_formatter->status_for( $e ),
|
||||
'code' => $error_formatter->error_code_for( $e ),
|
||||
'message' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
throw new BatchOperationFailed( 'Batch failed', $errors );
|
||||
}
|
||||
|
||||
$watermark = $this->repo->save( $collection );
|
||||
|
||||
if ( false === $watermark ) {
|
||||
throw new FatalError( 'Failed to save batch operations' );
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'results' => $results,
|
||||
'watermark' => $watermark,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalError If variable create fails or validation errors occur.
|
||||
*/
|
||||
public function create( array $data ): array {
|
||||
$collection = $this->repo->load();
|
||||
|
||||
$collection->assert_limit_not_reached();
|
||||
$collection->assert_label_is_unique( $data['label'] );
|
||||
|
||||
$id = $collection->next_id();
|
||||
$data['id'] = $id;
|
||||
|
||||
// TODO: we need to look into this maybe we dont need order to be sent from client. Just implemented as it was
|
||||
if ( ! isset( $data['order'] ) ) {
|
||||
$data['order'] = $collection->get_next_order();
|
||||
}
|
||||
|
||||
$variable = Variable::from_array( $data );
|
||||
|
||||
$collection->add_variable( $variable );
|
||||
|
||||
$watermark = $this->repo->save( $collection );
|
||||
|
||||
if ( false === $watermark ) {
|
||||
throw new FatalError( 'Failed to create variable' );
|
||||
}
|
||||
|
||||
return [
|
||||
'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
|
||||
'watermark' => $collection->watermark(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalError If variable update fails.
|
||||
*/
|
||||
public function update( string $id, array $data ): array {
|
||||
$collection = $this->repo->load();
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
if ( isset( $data['label'] ) ) {
|
||||
$collection->assert_label_is_unique( $data['label'], $id );
|
||||
}
|
||||
|
||||
$variable->apply_changes( $data );
|
||||
|
||||
$watermark = $this->repo->save( $collection );
|
||||
|
||||
if ( false === $watermark ) {
|
||||
throw new FatalError( 'Failed to update variable' );
|
||||
}
|
||||
|
||||
return [
|
||||
'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
|
||||
'watermark' => $watermark,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalError If variable delete fails.
|
||||
*/
|
||||
public function delete( string $id ) {
|
||||
$collection = $this->repo->load();
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
$variable->soft_delete();
|
||||
|
||||
$watermark = $this->repo->save( $collection );
|
||||
|
||||
if ( false === $watermark ) {
|
||||
throw new FatalError( 'Failed to delete variable' );
|
||||
}
|
||||
|
||||
return [
|
||||
'watermark' => $watermark,
|
||||
'variable' => array_merge( [
|
||||
'id' => $id,
|
||||
'deleted' => true,
|
||||
], $variable->to_array() ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FatalError If variable restore fails.
|
||||
*/
|
||||
public function restore( string $id, $overrides = [] ) {
|
||||
$collection = $this->repo->load();
|
||||
$variable = $collection->find_or_fail( $id );
|
||||
|
||||
$collection->assert_limit_not_reached();
|
||||
|
||||
if ( isset( $overrides['label'] ) ) {
|
||||
$collection->assert_label_is_unique( $overrides['label'], $variable->id() );
|
||||
}
|
||||
|
||||
$variable->apply_changes( $overrides );
|
||||
|
||||
$variable->restore();
|
||||
|
||||
$watermark = $this->repo->save( $collection );
|
||||
|
||||
if ( false === $watermark ) {
|
||||
throw new FatalError( 'Failed to delete variable' );
|
||||
}
|
||||
|
||||
return [
|
||||
'variable' => array_merge( [ 'id' => $id ], $variable->to_array() ),
|
||||
'watermark' => $watermark,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user