first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
<?php
namespace WPML\TM\Jobs;
use WPML\Core\WP\App\Resources;
use WPML\LIB\WP\Hooks;
use WPML\UIPage;
class Loader implements \IWPML_Backend_Action {
public function add_hooks() {
if ( wpml_is_ajax() ) {
return;
}
if ( UIPage::isTMJobs( $_GET ) || UIPage::isTranslationQueue( $_GET ) ) {
Hooks::onAction( 'wp_loaded' )
->then( [ $this, 'getData' ] )
->then( Resources::enqueueApp( 'jobs' ) );
}
}
public function getData() {
$data = ( new \WPML_TM_Jobs_List_Script_Data() )->get();
$data = ( new \WPML_TM_Scripts_Factory() )->build_localize_script_data( $data );
return [
'name' => 'WPML_TM_SETTINGS',
'data' => $data,
];
}
}

View File

@@ -0,0 +1,146 @@
<?php
namespace WPML\TM\Jobs;
use WPML\Element\API\PostTranslations;
use WPML\FP\Fns;
use WPML\FP\Maybe;
use WPML\FP\Obj;
use WPML\LIB\WP\User;
use WPML\Records\Translations as TranslationRecords;
use WPML\TM\API\Jobs;
use function WPML\FP\curryN;
use function WPML\FP\invoke;
use function WPML\FP\pipe;
class Manual {
/**
* @param array $params
*
* @return \WPML_Translation_Job|null
*/
public function createOrReuse( array $params ) {
$jobId = (int) filter_var( Obj::propOr( 0, 'job_id', $params ), FILTER_SANITIZE_NUMBER_INT );
list( $jobId, $trid, $updateNeeded, $targetLanguageCode, $elementType ) = $this->get_job_data_for_restore( $jobId, $params );
$sourceLangCode = filter_var( Obj::prop( 'source_language_code', $params ), FILTER_SANITIZE_FULL_SPECIAL_CHARS );
if ( $trid && $targetLanguageCode && ( $updateNeeded || ! $jobId ) ) {
$postId = $this->getOriginalPostId( $trid );
if ( $postId && $this->can_user_translate( $sourceLangCode, $targetLanguageCode, $postId ) ) {
return $this->markJobAsManual( $this->createLocalJob( $postId, $targetLanguageCode, $elementType ) );
}
}
return $jobId ? $this->markJobAsManual( wpml_tm_load_job_factory()->get_translation_job_as_active_record( $jobId ) ) : null;
}
private function getOriginalPostId( $trid ) {
return Obj::prop( 'element_id', TranslationRecords::getSourceByTrid( $trid ) );
}
/**
* @param $jobId
* @param array $params
*
* @return array ( job_id, trid, updated_needed, language_code, post_type )
*/
private function get_job_data_for_restore( $jobId, array $params ) {
$trid = (int) filter_var( Obj::prop( 'trid', $params ), FILTER_SANITIZE_NUMBER_INT );
$updateNeeded = (bool) filter_var( Obj::prop( 'update_needed', $params ), FILTER_SANITIZE_NUMBER_INT );
$languageCode = (string) filter_var( Obj::prop( 'language_code', $params ), FILTER_SANITIZE_FULL_SPECIAL_CHARS );
$job = null;
if ( $jobId ) {
$job = Jobs::get( $jobId );
} else if ( $trid && $languageCode ) {
$job = Jobs::getTridJob( $trid, $languageCode );
}
if ( $job ) {
return [
$jobId,
Obj::prop( 'trid', $job ),
Obj::prop( 'needs_update', $job ),
Obj::prop( 'language_code', $job ),
Obj::prop( 'original_post_type', $job )
];
}
$elementType = $trid ? Obj::path( [ 0, 'element_type' ], TranslationRecords::getByTrid( $trid ) ) : null;
return [ $jobId, $trid, $updateNeeded, $languageCode, $elementType, ];
}
/**
* @param string $sourceLangCode
* @param string $targetLangCode
* @param string $postId
*
* @return bool
*/
private function can_user_translate( $sourceLangCode, $targetLangCode, $postId ) {
$args = [
'lang_from' => $sourceLangCode,
'lang_to' => $targetLangCode,
'post_id' => $postId,
];
return wpml_tm_load_blog_translators()->is_translator( User::getCurrentId(), $args );
}
/**
* @param $originalPostId
* @param $targetLangCode
* @param $elementType
*
* @return \WPML_Translation_Job|null
*/
private function createLocalJob( $originalPostId, $targetLangCode, $elementType ) {
$jobId = wpml_tm_load_job_factory()->create_local_job( $originalPostId, $targetLangCode, null, $elementType );
return Maybe::fromNullable( $jobId )
->map( [ wpml_tm_load_job_factory(), 'get_translation_job_as_active_record' ] )
->map( $this->maybeAssignTranslator() )
->map( $this->maybeSetJobStatus() )
->getOrElse( null );
}
private function maybeAssignTranslator() {
return function ( $jobObject ) {
if ( $jobObject->get_translator_id() <= 0 ) {
$jobObject->assign_to( User::getCurrentId() );
}
return $jobObject;
};
}
private function maybeSetJobStatus() {
return function ( $jobObject ) {
if ( $this->isDuplicate( $jobObject ) ) {
Jobs::setStatus( (int) $jobObject->get_id(), ICL_TM_DUPLICATE );
} elseif ( (int) $jobObject->get_status_value() !== ICL_TM_COMPLETE ) {
Jobs::setStatus( (int) $jobObject->get_id(), ICL_TM_IN_PROGRESS );
}
return $jobObject;
};
}
private function markJobAsManual( $jobObject ) {
$jobObject && Jobs::clearAutomatic( $jobObject->get_id() );
return $jobObject;
}
private function isDuplicate( \WPML_Translation_Job $jobObject ) {
return Maybe::of( $jobObject->get_original_element_id() )
->map( PostTranslations::get() )
->map( Obj::prop( $jobObject->get_language_code() ) )
->map( Obj::prop( 'element_id' ) )
->map( [ wpml_get_post_status_helper(), 'is_duplicate' ] )
->getOrElse( false );
}
}

View File

@@ -0,0 +1,126 @@
<?php
class WPML_TM_Job_Element_Entity {
/** @var int */
private $id;
/** @var int */
private $content_id;
/** @var int */
private $timestamp;
/** @var string */
private $type;
/** @var string */
private $format;
/** @var bool */
private $translatable;
/** @var string */
private $data;
/** @var string */
private $data_translated;
/** @var bool */
private $finished;
/**
* @param int $id
* @param int $content_id
* @param int $timestamp
* @param string $type
* @param string $format
* @param bool $is_translatable
* @param string $data
* @param string $data_translated
* @param bool $finished
*/
public function __construct(
$id,
$content_id,
$timestamp,
$type,
$format,
$is_translatable,
$data,
$data_translated,
$finished
) {
$this->id = (int) $id;
$this->content_id = (int) $content_id;
$this->timestamp = (int) $timestamp;
$this->type = (string) $type;
$this->format = (string) $format;
$this->translatable = (bool) $is_translatable;
$this->data = (string) $data;
$this->data_translated = (bool) $data_translated;
$this->finished = (bool) $finished;
}
/**
* @return int
*/
public function get_id() {
return $this->id;
}
/**
* @return int
*/
public function get_content_id() {
return $this->content_id;
}
/**
* @return int
*/
public function get_timestamp() {
return $this->timestamp;
}
/**
* @return string
*/
public function get_type() {
return $this->type;
}
/**
* @return string
*/
public function get_format() {
return $this->format;
}
/**
* @return bool
*/
public function is_translatable() {
return $this->translatable;
}
/**
* @return string
*/
public function get_data() {
return $this->data;
}
/**
* @return string
*/
public function get_data_translated() {
return $this->data_translated;
}
/**
* @return bool
*/
public function is_finished() {
return $this->finished;
}
}

View File

@@ -0,0 +1,50 @@
<?php
class WPML_TM_Job_Elements_Repository {
/** @var wpdb */
private $wpdb;
/**
* @param wpdb $wpdb
*/
public function __construct( wpdb $wpdb ) {
$this->wpdb = $wpdb;
}
/**
* @param WPML_TM_Post_Job_Entity $job
*
* @return WPML_TM_Job_Element_Entity[]
*/
public function get_job_elements( WPML_TM_Post_Job_Entity $job ) {
$sql = "
SELECT translate.*
FROM {$this->wpdb->prefix}icl_translate translate
WHERE job_id = %d
";
$rowset = $this->wpdb->get_results( $this->wpdb->prepare( $sql, $job->get_translate_job_id() ) );
return array_map( array( $this, 'build_element_entity' ), $rowset );
}
/**
* @param stdClass $raw_data
*
* @return WPML_TM_Job_Element_Entity
*/
private function build_element_entity( stdClass $raw_data ) {
return new WPML_TM_Job_Element_Entity(
$raw_data->tid,
$raw_data->content_id,
$raw_data->timestamp,
$raw_data->field_type,
$raw_data->field_format,
$raw_data->field_translate,
$raw_data->field_data,
$raw_data->field_data_translated,
$raw_data->field_finished
);
}
}

View File

@@ -0,0 +1,362 @@
<?php
use WPML\FP\Lst;
class WPML_TM_Job_Entity {
const POST_TYPE = 'post';
const STRING_TYPE = 'string';
const STRING_BATCH = 'st-batch_strings';
const PACKAGE_TYPE = 'package';
/** @var int */
private $id;
/** @var string */
private $type;
/** @var int */
private $tp_id;
/** @var WPML_TM_Jobs_Batch */
private $batch;
/** @var int */
private $status;
/** @var int */
private $original_element_id;
/** @var string */
private $source_language;
/** @var string */
private $target_language;
/** @var string */
private $translation_service;
/** @var DateTime */
private $sent_date;
/** @var DateTime|null */
private $deadline;
/** @var int */
private $translator_id;
/** @var int */
private $revision;
/** @var WPML_TM_Job_TS_Status */
private $ts_status;
/** @var bool */
private $needs_update;
/** @var bool */
private $has_completed_translation = false;
/** @var string */
private $title;
/**
* @param int $id
* @param string $type
* @param int $tp_id
* @param WPML_TM_Jobs_Batch $batch
* @param int $status
*/
public function __construct( $id, $type, $tp_id, WPML_TM_Jobs_Batch $batch, $status ) {
$this->id = (int) $id;
if ( ! self::is_type_valid( $type ) ) {
throw new InvalidArgumentException( 'Invalid type value: ' . $type );
}
$this->type = $type;
$this->tp_id = (int) $tp_id;
$this->batch = $batch;
$this->set_status( $status );
}
/**
* @deprecated Use `get_rid` instead.
*
* This method is deprecated because it caused confusion
* between the `job_id` and the `rid`.
*
* It's actually returning the `rid`.
*
* @return int
*/
public function get_id() {
return $this->get_rid();
}
/**
* @return int
*/
public function get_rid() {
return $this->id;
}
/**
* @return string
*/
public function get_type() {
return $this->type;
}
/**
* @return int
*/
public function get_tp_id() {
return $this->tp_id;
}
/**
* @return WPML_TM_Jobs_Batch
*/
public function get_batch() {
return $this->batch;
}
/**
* @return int
*/
public function get_status() {
return $this->status;
}
/**
* @param int $status
*/
public function set_status( $status ) {
$status = (int) $status;
if ( ! in_array(
$status,
array(
ICL_TM_NOT_TRANSLATED,
ICL_TM_WAITING_FOR_TRANSLATOR,
ICL_TM_IN_PROGRESS,
ICL_TM_TRANSLATION_READY_TO_DOWNLOAD,
ICL_TM_DUPLICATE,
ICL_TM_COMPLETE,
ICL_TM_NEEDS_UPDATE,
ICL_TM_NEEDS_REVIEW,
ICL_TM_ATE_CANCELLED,
ICL_TM_ATE_NEEDS_RETRY,
),
true
) ) {
$status = ICL_TM_NOT_TRANSLATED;
}
$this->status = $status;
}
/**
* @return int
*/
public function get_original_element_id() {
return $this->original_element_id;
}
/**
* @param int $original_element_id
*/
public function set_original_element_id( $original_element_id ) {
$this->original_element_id = $original_element_id;
}
/**
* @return string
*/
public function get_source_language() {
return $this->source_language;
}
/**
* @param string $source_language
*/
public function set_source_language( $source_language ) {
$this->source_language = $source_language;
}
/**
* @return string
*/
public function get_target_language() {
return $this->target_language;
}
/**
* @param string $target_language
*/
public function set_target_language( $target_language ) {
$this->target_language = $target_language;
}
/**
* @return string
*/
public function get_translation_service() {
return $this->translation_service;
}
/**
* @param string $translation_service
*/
public function set_translation_service( $translation_service ) {
$this->translation_service = $translation_service;
}
/**
* @return DateTime
*/
public function get_sent_date() {
return $this->sent_date;
}
/**
* @param DateTime $sent_date
*/
public function set_sent_date( DateTime $sent_date ) {
$this->sent_date = $sent_date;
}
/**
* @param int $tp_id
*/
public function set_tp_id( $tp_id ) {
$this->tp_id = $tp_id;
}
/**
* @return DateTime|null
*/
public function get_deadline() {
return $this->deadline;
}
/**
* @param DateTime|null $deadline
*/
public function set_deadline( DateTime $deadline = null ) {
$this->deadline = $deadline;
}
/**
* @return int
*/
public function get_translator_id() {
return $this->translator_id;
}
/**
* @param int $translator_id
*
* @return self
*/
public function set_translator_id( $translator_id ) {
$this->translator_id = $translator_id;
return $this;
}
/**
* @return int
*/
public function get_revision() {
return $this->revision;
}
/**
* @param int $revision
*/
public function set_revision( $revision ) {
$this->revision = max( (int) $revision, 1 );
}
/**
* @return WPML_TM_Job_TS_Status
*/
public function get_ts_status() {
return $this->ts_status;
}
/**
* @param WPML_TM_Job_TS_Status|string $ts_status
*/
public function set_ts_status( $ts_status ) {
if ( is_string( $ts_status ) ) {
$status = json_decode( $ts_status );
if ( $status ) {
$ts_status = new WPML_TM_Job_TS_Status( $status->ts_status->status, $status->ts_status->links );
}
}
$this->ts_status = $ts_status;
}
/**
* @param WPML_TM_Job_Entity $job
*
* @return bool
*/
public function is_equal( WPML_TM_Job_Entity $job ) {
return $this->get_id() === $job->get_id() && $this->get_type() === $job->get_type();
}
/**
* @return bool
*/
public function does_need_update() {
return $this->needs_update;
}
/**
* @param bool $needs_update
*/
public function set_needs_update( $needs_update ) {
$this->needs_update = (bool) $needs_update;
}
/**
* @return bool
*/
public function has_completed_translation() {
return $this->has_completed_translation;
}
/**
* @param bool $has_completed_translation
*/
public function set_has_completed_translation( $has_completed_translation ) {
$this->has_completed_translation = (bool) $has_completed_translation;
}
/**
* @return string
*/
public function get_title() {
return $this->title;
}
/**
* @param string $title
*/
public function set_title( $title ) {
$this->title = $title;
}
/**
* @param string $type
*
* @return bool
*/
public static function is_type_valid( $type ) {
return Lst::includes( $type, [ self::POST_TYPE, self::STRING_TYPE, self::PACKAGE_TYPE, self::STRING_BATCH ] );
}
}

View File

@@ -0,0 +1,46 @@
<?php
class WPML_TM_Job_TS_Status {
/** @var string */
private $status;
/** @var array */
private $links = array();
/**
* WPML_TM_Job_TS_Status constructor.
*
* @param string $status
* @param array $links
*/
public function __construct( $status, $links ) {
$this->status = $status;
$this->links = $links;
}
/**
* @return string
*/
public function get_status() {
return $this->status;
}
/**
* @return array
*/
public function get_links() {
return $this->links;
}
public function __toString() {
if ( $this->status ) {
return wp_json_encode(
array(
'status' => $this->status,
'links' => $this->links,
)
);
}
return '';
}
}

View File

@@ -0,0 +1,44 @@
<?php
class WPML_TM_Jobs_Batch {
/** @var int */
private $id;
/** @var string */
private $name;
/** @var int|null */
private $tp_id;
/**
* @param int $id
* @param string $name
* @param int|null $tp_id
*/
public function __construct( $id, $name, $tp_id = null ) {
$this->id = (int) $id;
$this->name = (string) $name;
$this->tp_id = $tp_id ? (int) $tp_id : null;
}
/**
* @return int
*/
public function get_id() {
return $this->id;
}
/**
* @return string
*/
public function get_name() {
return $this->name;
}
/**
* @return int|null
*/
public function get_tp_id() {
return $this->tp_id;
}
}

View File

@@ -0,0 +1,131 @@
<?php
class WPML_TM_Jobs_Collection implements IteratorAggregate, Countable {
/** @var WPML_TM_Job_Entity[] */
private $jobs = array();
public function __construct( array $jobs ) {
foreach ( $jobs as $job ) {
if ( $job instanceof WPML_TM_Job_Entity ) {
$this->add( $job );
}
}
}
/**
* @param WPML_TM_Job_Entity $job
*/
private function add( WPML_TM_Job_Entity $job ) {
$this->jobs[] = $job;
}
/**
* @param int $tp_id
*
* @return null|WPML_TM_Job_Entity
*/
public function get_by_tp_id( $tp_id ) {
foreach ( $this->jobs as $job ) {
if ( $tp_id === $job->get_tp_id() ) {
return $job;
}
}
return null;
}
/**
* @param callable $callback
*
* @return WPML_TM_Jobs_Collection
*/
public function filter( $callback ) {
return new WPML_TM_Jobs_Collection( array_filter( $this->jobs, $callback ) );
}
/**
* @param array|int $status
* @param bool $exclude
*
* @return WPML_TM_Jobs_Collection
*/
public function filter_by_status( $status, $exclude = false ) {
if ( ! is_array( $status ) ) {
$status = array( $status );
}
$result = array();
if ( $exclude ) {
foreach ( $this->jobs as $job ) {
if ( ! in_array( $job->get_status(), $status, true ) ) {
$result[] = $job;
}
}
} else {
foreach ( $this->jobs as $job ) {
if ( in_array( $job->get_status(), $status, true ) ) {
$result[] = $job;
}
}
}
return new WPML_TM_Jobs_Collection( $result );
}
/**
* @param callable $callback
* @param bool $return_job_collection
*
* @return array|WPML_TM_Jobs_Collection
*/
public function map( $callback, $return_job_collection = false ) {
$mapped_result = array_map( $callback, $this->jobs );
return $return_job_collection ? new WPML_TM_Jobs_Collection( $mapped_result ) : $mapped_result;
}
public function map_to_property( $property ) {
$method = 'get_' . $property;
$result = array();
foreach ( $this->jobs as $job ) {
if ( ! method_exists( $job, $method ) ) {
throw new InvalidArgumentException( 'Property ' . $property . ' does not exist' );
}
$result[] = $job->{$method}();
}
return $result;
}
/**
* @param $jobs
*
* @return WPML_TM_Jobs_Collection
*/
public function append( $jobs ) {
if ( $jobs instanceof WPML_TM_Jobs_Collection ) {
$jobs = $jobs->toArray();
}
return new WPML_TM_Jobs_Collection( array_merge( $this->jobs, $jobs ) );
}
/**
* @return ArrayIterator
*/
#[\ReturnTypeWillChange]
public function getIterator() {
return new ArrayIterator( $this->jobs );
}
public function toArray() {
return $this->jobs;
}
#[\ReturnTypeWillChange]
public function count() {
return count( $this->jobs );
}
}

View File

@@ -0,0 +1,48 @@
<?php
class WPML_TM_Jobs_Date_Range {
/** @var DateTime|null */
private $begin;
/** @var DateTime|null */
private $end;
/**
* Specify how we should treat date values which are NULL
*
* @var bool
*/
private $include_null_date;
/**
* @param DateTime|null $begin
* @param DateTime|null $end
* @param bool $include_null_date
*/
public function __construct( DateTime $begin = null, DateTime $end = null, $include_null_date = false ) {
$this->begin = $begin;
$this->end = $end;
$this->include_null_date = (bool) $include_null_date;
}
/**
* @return DateTime|null
*/
public function get_begin() {
return $this->begin;
}
/**
* @return DateTime|null
*/
public function get_end() {
return $this->end;
}
/**
* @return bool
*/
public function is_include_null_date() {
return $this->include_null_date;
}
}

View File

@@ -0,0 +1,50 @@
<?php
class WPML_TM_Jobs_Needs_Update_Param {
const INCLUDE_NEEDS_UPDATE = 'include';
const EXCLUDE_NEEDS_UPDATE = 'exclude';
/** @var string */
private $value;
/**
* @param string $value
*/
public function __construct( $value ) {
if ( ! self::is_valid( $value ) ) {
throw new \InvalidArgumentException( 'Invalid value of NEEDS_UPDATE param: ' . $value );
}
$this->value = $value;
}
/**
* @return bool
*/
public function is_needs_update_excluded() {
return $this->value === self::EXCLUDE_NEEDS_UPDATE;
}
/**
* @return bool
*/
public function is_needs_update_included() {
return $this->value === self::INCLUDE_NEEDS_UPDATE;
}
/**
* @param string $value
*
* @return bool
*/
public static function is_valid( $value ) {
return in_array(
(string) $value,
[
self::INCLUDE_NEEDS_UPDATE,
self::EXCLUDE_NEEDS_UPDATE,
],
true
);
}
}

View File

@@ -0,0 +1,164 @@
<?php
use \WPML\TM\Jobs\Query\Query;
use WPML\FP\Fns;
class WPML_TM_Jobs_Repository {
/** @var wpdb */
private $wpdb;
/** @var Query */
private $query_builder;
/** @var WPML_TM_Job_Elements_Repository */
private $elements_repository;
/**
* @param wpdb $wpdb
* @param Query $query_builder
* @param WPML_TM_Job_Elements_Repository $elements_repository
*/
public function __construct(
wpdb $wpdb,
Query $query_builder,
WPML_TM_Job_Elements_Repository $elements_repository
) {
$this->wpdb = $wpdb;
$this->query_builder = $query_builder;
$this->elements_repository = $elements_repository;
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return WPML_TM_Jobs_Collection|array
*/
public function get( WPML_TM_Jobs_Search_Params $params ) {
if ( $params->get_columns_to_select() ) {
return $this->wpdb->get_results( $this->query_builder->get_data_query( $params ) );
}
return new WPML_TM_Jobs_Collection( array_map(
array( $this, 'build_job_entity' ),
$this->wpdb->get_results( $this->query_builder->get_data_query( $params ) )
) );
}
/**
* @param array $ateJobIds
*
* @return bool
*/
public function increment_ate_sync_count( array $ateJobIds ) {
if ( empty( $ateJobIds ) ) {
return true;
} else {
$query = sprintf(
'UPDATE %sicl_translate_job SET ate_sync_count=ate_sync_count+1 WHERE editor_job_id IN( %s )',
$this->wpdb->prefix,
wpml_prepare_in( $ateJobIds )
);
return (bool) $this->wpdb->query( $query );
}
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return int
*/
public function get_count( WPML_TM_Jobs_Search_Params $params ) {
return (int) $this->wpdb->get_var( $this->query_builder->get_count_query( $params ) );
}
/**
* @param int $local_job_id
* @param string $job_type
*
* @throws InvalidArgumentException
* @return WPML_TM_Job_Entity|false
*/
public function get_job( $local_job_id, $job_type ) {
$params = new WPML_TM_Jobs_Search_Params();
$params->set_local_job_id( $local_job_id );
$params->set_job_types( $job_type );
$data = $this->wpdb->get_row( $this->query_builder->get_data_query( $params ) );
if ( $data ) {
$data = $this->build_job_entity( $data );
}
return $data;
}
/**
* @param stdClass $raw_data
*
* @return WPML_TM_Job_Entity
*/
private function build_job_entity( stdClass $raw_data ) {
$types = [ WPML_TM_Job_Entity::POST_TYPE, WPML_TM_Job_Entity::PACKAGE_TYPE, WPML_TM_Job_Entity::STRING_BATCH ];
$batch = new WPML_TM_Jobs_Batch( $raw_data->local_batch_id, $raw_data->batch_name, $raw_data->tp_batch_id );
if ( in_array( $raw_data->type, $types, true ) ) {
$job = new WPML_TM_Post_Job_Entity(
$raw_data->id,
$raw_data->type,
$raw_data->tp_id,
$batch,
(int) $raw_data->status,
array( $this->elements_repository, 'get_job_elements' )
);
$job->set_translate_job_id( $raw_data->translate_job_id );
$job->set_editor( $raw_data->editor );
$job->set_completed_date( $raw_data->completed_date ? new DateTime( $raw_data->completed_date ) : null );
$job->set_editor_job_id( $raw_data->editor_job_id );
$job->set_automatic( $raw_data->automatic );
$job->set_review_status( $raw_data->review_status );
$job->set_trid( $raw_data->trid );
$job->set_element_type( $raw_data->element_type );
$job->set_element_id( $raw_data->element_id );
$job->set_element_type_prefix( $raw_data->element_type );
$job->set_job_title( $raw_data->job_title );
} else {
$job = new WPML_TM_Job_Entity(
$raw_data->id,
$raw_data->type,
$raw_data->tp_id,
$batch,
(int) $raw_data->status
);
}
$job->set_original_element_id( $raw_data->original_element_id );
$job->set_source_language( $raw_data->source_language );
$job->set_target_language( $raw_data->target_language );
$job->set_translation_service( $raw_data->translation_service );
$job->set_sent_date( new DateTime( $raw_data->sent_date ) );
$job->set_deadline( $this->get_deadline( $raw_data ) );
$job->set_translator_id( $raw_data->translator_id );
$job->set_revision( $raw_data->revision );
$job->set_ts_status( $raw_data->ts_status );
$job->set_needs_update( $raw_data->needs_update );
$job->set_has_completed_translation( $raw_data->has_completed_translation );
$job->set_title( $raw_data->title );
return $job;
}
/**
* @param stdClass $raw_data
*
* @return DateTime|null
*/
private function get_deadline( stdClass $raw_data ) {
if ( $raw_data->deadline_date && '0000-00-00 00:00:00' !== $raw_data->deadline_date ) {
return new DateTime( $raw_data->deadline_date );
}
return null;
}
}

View File

@@ -0,0 +1,691 @@
<?php
class WPML_TM_Jobs_Search_Params {
const SCOPE_REMOTE = 'remote';
const SCOPE_LOCAL = 'local';
const SCOPE_ALL = 'all';
const SCOPE_ATE = 'ate';
private static $scopes = array(
self::SCOPE_LOCAL,
self::SCOPE_REMOTE,
self::SCOPE_ALL,
self::SCOPE_ATE,
);
/** @var array */
private $status = array();
/** @var WPML_TM_Jobs_Needs_Update_Param|null */
private $needs_update;
/** @var string */
private $scope = self::SCOPE_ALL;
/** @var array */
private $job_types = array();
/** @var int[] */
private $local_job_ids;
/** @var int */
private $limit;
/** @var int */
private $offset;
/** @var int */
private $id;
/** @var string[] */
private $title;
/** @var string[] */
private $batch_name;
/** @var string */
private $source_language;
/** @var string[] */
private $target_language;
/** @var array */
private $tp_id = '';
/** @var WPML_TM_Jobs_Sorting_Param[] */
private $sorting = array();
/** @var int */
private $translated_by;
/** @var WPML_TM_Jobs_Date_Range */
private $deadline;
/** @var WPML_TM_Jobs_Date_Range */
private $sent;
/** @var WPML_TM_Jobs_Date_Range */
private $completed_date;
/** @var int */
private $original_element_id;
/** @var bool|null */
private $needs_review = null;
/** @var bool */
private $exclude_hidden_jobs = true;
/** @var int */
private $max_ate_retries;
/** @var bool */
private $exclude_manual = false;
/** @var bool */
private $exclude_longstanding = false;
/** @var bool */
private $exclude_cancelled = false;
/**
* Corresponds with `wp_icl_translations.element_type` column
*
* @var string
*/
private $element_type;
/** @var null|array */
private $columns_to_select = null;
/** @var array */
private $custom_where_conditions = [];
public function __construct( array $params = array() ) {
if ( array_key_exists( 'limit', $params ) ) {
$this->set_limit( $params['limit'] );
if ( array_key_exists( 'offset', $params ) ) {
$this->set_offset( $params['offset'] );
}
}
$fields = array(
'status',
'scope',
'job_types',
'local_job_id',
'id',
'title',
'batch_name',
'source_language',
'target_language',
'sorting',
'tp_id',
'translated_by',
'deadline',
'completed_date',
'sent',
'original_element_id',
'exclude_manual',
'exclude_longstanding',
);
foreach ( $fields as $field ) {
if ( array_key_exists( $field, $params ) ) {
$this->{'set_' . $field}( $params[ $field ] );
}
}
}
/**
* @return array
*/
public function get_status() {
return $this->status;
}
/**
* @param array $status
*
* @return self
*/
public function set_status( array $status ) {
$this->status = array_map( 'intval', array_values( array_filter( $status, 'is_numeric' ) ) );
return $this;
}
/**
* @return string
*/
public function get_scope() {
return $this->scope;
}
/**
* @return array
*/
public function get_tp_id() {
return $this->tp_id;
}
/**
* @param string $scope
*
* @retun self
*/
public function set_scope( $scope ) {
if ( ! $this->is_valid_scope( $scope ) ) {
throw new InvalidArgumentException(
'Invalid scope. Accepted values: ' . implode( ', ', self::$scopes )
);
}
$this->scope = $scope;
return $this;
}
/**
* @return array
*/
public function get_job_types() {
return $this->job_types;
}
/**
* @param int|array $tp_id
*
* @return $this
*/
public function set_tp_id( $tp_id ) {
$this->tp_id = is_array( $tp_id ) ? $tp_id : array( $tp_id );
return $this;
}
/**
* @param string|array $job_types
*
* @return self
*/
public function set_job_types( $job_types ) {
$correct_types = [
WPML_TM_Job_Entity::POST_TYPE,
WPML_TM_Job_Entity::PACKAGE_TYPE,
WPML_TM_Job_Entity::STRING_TYPE,
WPML_TM_Job_Entity::STRING_BATCH,
];
if ( ! is_array( $job_types ) ) {
$job_types = array( $job_types );
}
foreach ( $job_types as $job_type ) {
if ( ! in_array( $job_type, $correct_types, true ) ) {
throw new InvalidArgumentException( 'Invalid job type' );
}
$this->job_types[] = $job_type;
}
return $this;
}
/**
* @return int|null
*/
public function get_first_local_job_id() {
return ! empty( $this->local_job_ids ) ? current( $this->local_job_ids ) : null;
}
/**
* @return int[]
*/
public function get_local_job_ids() {
return $this->local_job_ids;
}
/**
* @param int $local_job_id
*
* @return self
*/
public function set_local_job_id( $local_job_id ) {
$this->local_job_ids[] = (int) $local_job_id;
return $this;
}
/**
* @param int[] $local_job_ids
*
* @return self
*/
public function set_local_job_ids( array $local_job_ids ) {
$this->local_job_ids = array_map( 'intval', $local_job_ids );
return $this;
}
/**
* @return int
*/
public function get_limit() {
return $this->limit;
}
/**
* @param int $limit
*
* @return self
*/
public function set_limit( $limit ) {
$this->limit = $limit;
return $this;
}
/**
* @return int
*/
public function get_offset() {
return $this->offset;
}
/**
* @param int $offset
*
* @return self
*/
public function set_offset( $offset ) {
$this->offset = $offset;
return $this;
}
/**
* @return int
*/
public function get_id() {
return $this->id;
}
/**
* @param int $id
*
* @return self
*/
public function set_id( $id ) {
$this->id = $id;
return $this;
}
/**
* @return string[]
*/
public function get_title() {
return $this->title;
}
/**
* @param array|string $title
*
* @return self
*/
public function set_title( $title ) {
$this->title = is_array( $title ) ? $title : array( $title );
return $this;
}
/**
* @return string[]
*/
public function get_batch_name() {
return $this->batch_name;
}
/**
* @param string[] $batch_name
*/
public function set_batch_name( $batch_name ) {
$this->batch_name = $batch_name;
}
/**
* @return string
*/
public function get_source_language() {
return $this->source_language;
}
/**
* @param string $source_language
*
* @return self
*/
public function set_source_language( $source_language ) {
$this->source_language = $source_language;
return $this;
}
/**
* @return string[]
*/
public function get_target_language() {
return $this->target_language;
}
/**
* @param array|string $target_language
*
* @return self
*/
public function set_target_language( $target_language ) {
$this->target_language = is_array( $target_language ) ? $target_language : array( $target_language );
return $this;
}
/**
* @return WPML_TM_Jobs_Sorting_Param[]
*/
public function get_sorting() {
return $this->sorting;
}
/**
* @param WPML_TM_Jobs_Sorting_Param[] $sorting
*
* @return self
*/
public function set_sorting( array $sorting ) {
$this->sorting = array();
foreach ( $sorting as $sorting_param ) {
if ( $sorting_param instanceof WPML_TM_Jobs_Sorting_Param ) {
$this->sorting[] = $sorting_param;
}
}
return $this;
}
/**
* @return int
*/
public function get_translated_by() {
return $this->translated_by;
}
/**
* @param int|null $translated_by
*
* @return self
*/
public function set_translated_by( $translated_by ) {
$this->translated_by = (int) $translated_by;
return $this;
}
/**
* @return WPML_TM_Jobs_Date_Range
*/
public function get_deadline() {
return $this->deadline;
}
/**
* @param WPML_TM_Jobs_Date_Range $deadline
*
* @return self
*/
public function set_deadline( WPML_TM_Jobs_Date_Range $deadline ) {
$this->deadline = $deadline;
return $this;
}
/**
* @return WPML_TM_Jobs_Date_Range
*/
public function get_sent() {
return $this->sent;
}
/**
* @return WPML_TM_Jobs_Date_Range
*/
public function get_completed_date() {
return $this->completed_date;
}
/**
* @return int
*/
public function get_original_element_id() {
return $this->original_element_id;
}
/**
* @param WPML_TM_Jobs_Date_Range $sent
*
* @return self
*/
public function set_sent( WPML_TM_Jobs_Date_Range $sent ) {
$this->sent = $sent;
return $this;
}
/**
* @param WPML_TM_Jobs_Date_Range $completed_date
*
* @return self
*/
public function set_completed_date( WPML_TM_Jobs_Date_Range $completed_date ) {
$this->completed_date = $completed_date;
return $this;
}
/**
* @param int $original_element_id
*
* @return $this
*/
public function set_original_element_id( $original_element_id ) {
$this->original_element_id = $original_element_id;
return $this;
}
/**
* @return WPML_TM_Jobs_Needs_Update_Param|null
*/
public function get_needs_update() {
return $this->needs_update;
}
/**
* @param WPML_TM_Jobs_Needs_Update_Param|null $needs_update
*
* @return $this
*/
public function set_needs_update( WPML_TM_Jobs_Needs_Update_Param $needs_update = null ) {
$this->needs_update = $needs_update;
return $this;
}
/**
* @return bool
*/
public function needs_review() {
return $this->needs_review;
}
/**
* @return bool
*/
public function exclude_hidden_jobs() {
return $this->exclude_hidden_jobs;
}
/**
* @param int $max_ate_retries
*
* @return $this
*/
public function set_max_ate_retries( $max_ate_retries ) {
$this->max_ate_retries = $max_ate_retries;
return $this;
}
/**
* @return int
*/
public function get_max_ate_retries() {
return $this->max_ate_retries;
}
/**
* If value is set to NULL then the filter is ignored
* If value is true then we INCLUDE needs review jobs
* If value is false then we EXCLUDE needs review jobs
*
* @param bool|null $needs_review
*/
public function set_needs_review( $needs_review = true ) {
$this->needs_review = $needs_review;
return $this;
}
/**
* @param bool $exclude_hidden_jobs
*/
public function set_exclude_hidden_jobs( $exclude_hidden_jobs ) {
$this->exclude_hidden_jobs = $exclude_hidden_jobs;
return $this;
}
/**
* @param mixed $value
*
* @return bool
*/
public static function is_valid_scope( $value ) {
return in_array(
$value,
self::$scopes,
true
);
}
/**
* @param bool $excludeManual
*/
public function set_exclude_manual( $excludeManual ) {
$this->exclude_manual = $excludeManual;
}
/**
* @return bool
*/
public function should_exclude_manual() {
return $this->exclude_manual;
}
/**
* @param bool $excludeLongstanding
*/
public function set_exclude_longstanding( $excludeLongstanding ) {
$this->exclude_longstanding = $excludeLongstanding;
}
/**
* @return bool
*/
public function should_exclude_longstanding() {
return $this->exclude_longstanding;
}
/**
* @return array|null
*/
public function get_columns_to_select() {
return $this->columns_to_select;
}
/**
* @param array|null $columns_to_select
*
* @retun $this
*/
public function set_columns_to_select( $columns_to_select ) {
$this->columns_to_select = $columns_to_select;
return $this;
}
/**
* @return string
*/
public function get_element_type() {
return $this->element_type;
}
/**
* @param string $element_type
*
* @retrun $this
*/
public function set_element_type( $element_type ) {
$this->element_type = $element_type;
return $this;
}
/**
* @return bool
*/
public function should_exclude_cancelled() {
return $this->exclude_cancelled;
}
/**
* @param bool $exclude_cancelled
*
* @return $this
*/
public function set_exclude_cancelled( $exclude_cancelled = true ) {
$this->exclude_cancelled = $exclude_cancelled;
return $this;
}
/**
* @return array
*/
public function get_custom_where_conditions() {
return $this->custom_where_conditions;
}
/**
* @param array $custom_where_conditions
*
* @retun $this
*/
public function set_custom_where_conditions( $custom_where_conditions ) {
$this->custom_where_conditions = $custom_where_conditions;
return $this;
}
}

View File

@@ -0,0 +1,37 @@
<?php
class WPML_TM_Jobs_Sorting_Param {
/** @var string */
private $column;
/** @var string */
private $direction;
/**
* @param string $column
* @param string $direction
*/
public function __construct( $column, $direction = 'asc' ) {
$direction = strtolower( $direction );
if ( 'asc' !== $direction && 'desc' !== $direction ) {
$direction = 'asc';
}
$this->column = $column;
$this->direction = $direction;
}
/**
* @return string
*/
public function get_column() {
return $this->column;
}
/**
* @return string
*/
public function get_direction() {
return $this->direction;
}
}

View File

@@ -0,0 +1,228 @@
<?php
class WPML_TM_Post_Job_Entity extends WPML_TM_Job_Entity {
/** @var WPML_TM_Job_Element_Entity[]|callable */
private $elements;
/** @var int */
private $translate_job_id;
/** @var string */
private $editor;
/** @var int */
private $editor_job_id;
/** @var null|DateTime */
private $completed_date;
/** @var bool */
private $automatic;
/** @var null|string */
private $review_status = null;
/** @var int */
private $trid;
/** @var string */
private $element_type;
/** @var int */
private $element_id;
/** @var string */
private $element_type_prefix;
/** @var string */
private $job_title;
public function __construct( $id, $type, $tp_id, $batch, $status, $elements ) {
parent::__construct( $id, $type, $tp_id, $batch, $status );
if ( is_callable( $elements ) ) {
$this->elements = $elements;
} elseif ( is_array( $elements ) ) {
foreach ( $elements as $element ) {
if ( $element instanceof WPML_TM_Job_Element_Entity ) {
$this->elements[] = $element;
}
}
}
}
/**
* @return WPML_TM_Job_Element_Entity[]
*/
public function get_elements() {
if ( is_callable( $this->elements ) ) {
return call_user_func( $this->elements, $this );
} elseif ( is_array( $this->elements ) ) {
return $this->elements;
} else {
return array();
}
}
/**
* @return int
*/
public function get_translate_job_id() {
return $this->translate_job_id;
}
/**
* @param int $translate_job_id
*/
public function set_translate_job_id( $translate_job_id ) {
$this->translate_job_id = (int) $translate_job_id;
}
/**
* @return string
*/
public function get_editor() {
return $this->editor;
}
/**
* @param string $editor
*/
public function set_editor( $editor ) {
$this->editor = (string) $editor;
}
/**
* @return int
*/
public function get_editor_job_id() {
return $this->editor_job_id;
}
/**
* @param int $editor_job_id
*/
public function set_editor_job_id( $editor_job_id ) {
$this->editor_job_id = (int) $editor_job_id;
}
/**
* @return bool
*/
public function is_ate_job() {
return 'local' === $this->get_translation_service() && $this->is_ate_editor();
}
/**
* @return bool
*/
public function is_ate_editor() {
return WPML_TM_Editors::ATE === $this->get_editor();
}
/**
* @return DateTime|null
*/
public function get_completed_date() {
return $this->completed_date;
}
/**
* @param DateTime|null $completed_date
*/
public function set_completed_date( DateTime $completed_date = null ) {
$this->completed_date = $completed_date;
}
/**
* @return bool
*/
public function is_automatic() {
return $this->automatic;
}
/**
* @param bool $automatic
*/
public function set_automatic( $automatic ) {
$this->automatic = (bool) $automatic;
}
/**
* @return string|null
*/
public function get_review_status() {
return $this->review_status;
}
/**
* @param string|null $review_status
*/
public function set_review_status( $review_status ) {
$this->review_status = $review_status;
}
/**
* @return int
*/
public function get_trid() {
return $this->trid;
}
/**
* @param int $trid
*/
public function set_trid( $trid ) {
$this->trid = $trid;
}
/**
* @return string
*/
public function get_element_type() {
return $this->element_type;
}
/**
* @param string $element_type
*/
public function set_element_type( $element_type ) {
$this->element_type = $element_type;
}
/**
* @return int
*/
public function get_element_id() {
return $this->element_id;
}
/**
* @param int $element_id
*/
public function set_element_id( $element_id ) {
$this->element_id = $element_id;
}
public function get_element_type_prefix() {
return $this->element_type_prefix;
}
public function set_element_type_prefix( $element_type ) {
$this->element_type_prefix = explode( '_', $element_type )[0];
}
/**
* @return string
*/
public function get_job_title() {
return $this->job_title;
}
/**
* @param string $job_title
*/
public function set_job_title( $job_title ) {
$this->job_title = $job_title;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPML\TM\Jobs\Endpoint;
use WPML\Ajax\IHandler;
use WPML\Collect\Support\Collection;
use WPML\FP\Either;
use WPML\FP\Fns;
use WPML\TM\API\Jobs;
class Resign implements IHandler {
public function run( Collection $data ) {
$result = \wpml_collect( $data->get( 'jobIds' ) )
->filter( Jobs::get() )
->map( Fns::tap( [ wpml_load_core_tm(), 'resign_translator' ] ) )
->values()
->toArray();
return Either::of( $result );
}
}

View File

@@ -0,0 +1,282 @@
<?php
namespace WPML\TM\Jobs\Query;
use wpdb;
use WPML_TM_Editors;
use WPML_TM_Jobs_Search_Params;
use WPML\TM\ATE\Jobs;
abstract class AbstractQuery implements Query {
/** @var wpdb */
protected $wpdb;
/** @var QueryBuilder */
protected $query_builder;
/** @var string */
protected $title_column = 'posts.post_title';
/** @var string */
protected $batch_name_column = 'batches.batch_name';
/**
* @param wpdb $wpdb
* @param QueryBuilder $query_builder
*/
public function __construct( wpdb $wpdb, QueryBuilder $query_builder ) {
$this->wpdb = $wpdb;
$this->query_builder = $query_builder;
}
public function get_data_query( WPML_TM_Jobs_Search_Params $params ) {
$has_completed_translation_subquery = "
SELECT COUNT(job_id)
FROM {$this->wpdb->prefix}icl_translate_job as copmpleted_translation_job
WHERE copmpleted_translation_job.rid = translation_status.rid AND copmpleted_translation_job.translated = 1
";
if ( $params->get_columns_to_select() ) {
$columns = $params->get_columns_to_select();
} else {
$columns = [
'translation_status.rid AS id',
"'" . $this->get_type() . "' AS type",
'translation_status.tp_id AS tp_id',
'batches.id AS local_batch_id',
'batches.tp_id AS tp_batch_id',
$this->batch_name_column,
'translation_status.status AS status',
'original_translations.element_id AS original_element_id',
'translations.source_language_code AS source_language',
'translations.language_code AS target_language',
'translations.trid',
'translations.element_type',
'translations.element_id',
'translation_status.translation_service AS translation_service',
'translation_status.timestamp AS sent_date',
'translate_job.deadline_date AS deadline_date',
'translate_job.completed_date AS completed_date',
"{$this->title_column} AS title",
'source_languages.english_name AS source_language_name',
'target_languages.english_name AS target_language_name',
'translate_job.translator_id AS translator_id',
'translate_job.job_id AS translate_job_id',
'translation_status.tp_revision AS revision',
'translation_status.ts_status AS ts_status',
'translation_status.needs_update AS needs_update',
'translate_job.editor AS editor',
"({$has_completed_translation_subquery}) > 0 AS has_completed_translation",
'translate_job.editor_job_id AS editor_job_id',
'translate_job.automatic AS automatic',
'translate_job.title AS job_title',
'translation_status.review_status AS review_status',
];
}
return $this->build_query( $params, $columns );
}
public function get_count_query( WPML_TM_Jobs_Search_Params $params ) {
$columns = array( 'COUNT(translation_status.rid)' );
return $this->build_query( $params, $columns );
}
/**
* @param WPML_TM_Jobs_Search_Params $params
* @param array $columns
*
* @return string
*/
protected function build_query( WPML_TM_Jobs_Search_Params $params, array $columns ) {
if ( $this->check_job_type( $params ) ) {
return '';
}
$query_builder = clone $this->query_builder;
$query_builder->set_columns( $columns );
$query_builder->set_from( "{$this->wpdb->prefix}icl_translation_status translation_status" );
$this->define_joins( $query_builder );
$this->define_filters( $query_builder, $params );
$query_builder->set_limit( $params );
$query_builder->set_order( $params );
return $query_builder->build();
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return bool
*/
protected function check_job_type( WPML_TM_Jobs_Search_Params $params ) {
return $params->get_job_types() && ! in_array( $this->get_type(), $params->get_job_types(), true );
}
/**
* @return string
*/
abstract protected function get_type();
protected function define_joins( QueryBuilder $query_builder ) {
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_translations translations
ON translations.translation_id = translation_status.translation_id"
);
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_translations original_translations
ON original_translations.trid = translations.trid AND original_translations.language_code = translations.source_language_code"
);
$subquery = "
SELECT *
FROM {$this->wpdb->prefix}icl_translate_job as translate_job
WHERE job_id = (
SELECT MAX(job_id) AS job_id
FROM {$this->wpdb->prefix}icl_translate_job as sub_translate_job
WHERE sub_translate_job.rid = translate_job.rid
)
";
$query_builder->add_join( "INNER JOIN ({$subquery}) AS translate_job ON translate_job.rid = translation_status.rid" );
$this->add_resource_join( $query_builder );
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_languages source_languages
ON source_languages.code = translations.source_language_code"
);
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_languages target_languages
ON target_languages.code = translations.language_code"
);
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_translation_batches batches
ON batches.id = translation_status.batch_id"
);
}
abstract protected function add_resource_join( QueryBuilder $query_builder );
protected function define_filters( QueryBuilder $query_builder, WPML_TM_Jobs_Search_Params $params ) {
$this->set_status_filter( $query_builder, $params );
$query_builder = $this->set_scope_filter( $query_builder, $params );
$query_builder->set_multi_value_text_filter( $this->title_column, $params->get_title() );
$query_builder->set_multi_value_text_filter( $this->batch_name_column, $params->get_batch_name() );
$query_builder->set_source_language( 'translations.source_language_code', $params );
$query_builder->set_target_language( 'translations.language_code', $params );
$query_builder->set_translated_by_filter(
'translate_job.translator_id',
'translation_status.translation_service',
$params
);
if ( $params->get_sent() ) {
$query_builder->set_date_range( 'translation_status.timestamp', $params->get_sent() );
}
if ( $params->get_deadline() ) {
$query_builder->set_date_range( 'translate_job.deadline_date', $params->get_deadline() );
}
if ( $params->get_completed_date() ) {
$query_builder->set_date_range( 'translate_job.completed_date', $params->get_completed_date() );
}
$query_builder->set_numeric_value_filter( 'translation_status.rid', $params->get_id() );
$query_builder->set_numeric_value_filter( 'translation_status.rid', $params->get_local_job_ids() );
$query_builder->set_numeric_value_filter(
'original_translations.element_id',
$params->get_original_element_id()
);
$query_builder->set_tp_id_filter( 'translation_status.tp_id', $params );
if ( $params->needs_review() ) {
$query_builder->set_needs_review();
} elseif ( $params->needs_review() === false ) {
$query_builder->set_do_not_need_review();
}
if ( $params->should_exclude_manual() ) {
$query_builder->set_automatic();
}
if ( $params->should_exclude_longstanding() ) {
$query_builder->set_max_ate_sync_count( Jobs::LONGSTANDING_AT_ATE_SYNC_COUNT );
}
if ( $params->get_max_ate_retries() ) {
$query_builder->set_max_retries( $params->get_max_ate_retries() );
}
if ( $params->exclude_hidden_jobs() ) {
$query_builder->set_set_excluded_jobs();
}
if ( $params->get_element_type() ) {
$query_builder->set_element_type( $params->get_element_type() );
}
if ( $params->get_custom_where_conditions() ) {
foreach ( $params->get_custom_where_conditions() as $whereCondition ) {
$query_builder->add_AND_where_condition( $whereCondition );
}
}
}
private function set_status_filter(
QueryBuilder $query_builder,
WPML_TM_Jobs_Search_Params $params
) {
if ( $params->get_needs_update() ) {
$statuses = array_diff( $params->get_status(), [ ICL_TM_NEEDS_UPDATE ] );
if ( $params->get_needs_update()->is_needs_update_excluded() ) {
$query_builder->add_AND_where_condition( 'translation_status.needs_update != 1' );
if ( $statuses ) {
$query_builder->set_status_filter( 'translation_status.status', $params );
}
} else {
if ( $statuses ) {
$statuses = wpml_prepare_in( $params->get_status(), '%d' );
$statuses = sprintf( 'translation_status.status IN (%s)', $statuses );
$query_builder->add_AND_where_condition( "( translation_status.needs_update = 1 OR {$statuses} )" );
} else {
$query_builder->add_AND_where_condition( 'translation_status.needs_update = 1' );
}
}
} else {
$query_builder->set_status_filter( 'translation_status.status', $params );
}
if ( $params->should_exclude_cancelled() ) {
$query_builder->add_AND_where_condition( 'translation_status.status != 0' );
}
}
private function set_scope_filter( QueryBuilder $query_builder, WPML_TM_Jobs_Search_Params $params ) {
switch ( $params->get_scope() ) {
case WPML_TM_Jobs_Search_Params::SCOPE_LOCAL:
$query_builder->add_AND_where_condition( "translation_status.translation_service = 'local'" );
break;
case WPML_TM_Jobs_Search_Params::SCOPE_REMOTE:
$query_builder->add_AND_where_condition( "translation_status.translation_service != 'local'" );
break;
case WPML_TM_Jobs_Search_Params::SCOPE_ATE:
$query_builder->add_AND_where_condition( "translation_status.translation_service = 'local'" );
$query_builder->add_AND_where_condition( $this->wpdb->prepare( 'translate_job.editor = %s', WPML_TM_Editors::ATE ) );
break;
}
return $query_builder;
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace WPML\TM\Jobs\Query;
use \InvalidArgumentException;
use \WPML_TM_Jobs_Search_Params;
use \RuntimeException;
class CompositeQuery implements Query {
const METHOD_UNION = 'union';
const METHOD_COUNT = 'count';
/**
* Job queries
*
* @var Query[]
*/
private $queries;
/**
* Limit query helper
*
* @var LimitQueryHelper
*/
private $limit_query_helper;
/**
* Order query helper
*
* @var OrderQueryHelper
*/
private $order_query_helper;
/**
* @param Query[] $queries Job queries.
* @param LimitQueryHelper $limit_helper Limit helper.
* @param OrderQueryHelper $order_helper Order helper.
*
* @throws InvalidArgumentException In case of error.
*/
public function __construct(
array $queries,
LimitQueryHelper $limit_helper,
OrderQueryHelper $order_helper
) {
$queries = array_filter( $queries, array( $this, 'is_query_valid' ) );
if ( empty( $queries ) ) {
throw new InvalidArgumentException( 'Collection of sub-queries is empty or contains only invalid elements' );
}
$this->queries = $queries;
$this->limit_query_helper = $limit_helper;
$this->order_query_helper = $order_helper;
}
/**
* Get data query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @throws InvalidArgumentException In case of error.
* @return string
*/
public function get_data_query( WPML_TM_Jobs_Search_Params $params ) {
if ( ! $params->get_job_types() ) {
// We are merging subqueries here, that's why LIMIT must be applied to final query.
$params_without_pagination_and_sorting = clone $params;
$params_without_pagination_and_sorting->set_limit( 0 )->set_offset( 0 );
$params_without_pagination_and_sorting->set_sorting( array() );
$query = $this->get_sql( $params_without_pagination_and_sorting, self::METHOD_UNION );
$order = $this->order_query_helper->get_order( $params );
if ( $order ) {
$query .= ' ' . $order;
}
$limit = $this->limit_query_helper->get_limit( $params );
if ( $limit ) {
$query .= ' ' . $limit;
}
return $query;
} else {
return $this->get_sql( $params, self::METHOD_UNION );
}
}
/**
* Get count query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @return int|string
*/
public function get_count_query( WPML_TM_Jobs_Search_Params $params ) {
$params_without_pagination_and_sorting = clone $params;
$params_without_pagination_and_sorting->set_limit( 0 )->set_offset( 0 );
$params_without_pagination_and_sorting->set_sorting( array() );
return $this->get_sql( $params_without_pagination_and_sorting, self::METHOD_COUNT );
}
/**
* Get SQL request string
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
* @param string $method Query method.
*
* @throws InvalidArgumentException In case of error.
* @throws RuntimeException In case of error.
* @return string
*/
private function get_sql( WPML_TM_Jobs_Search_Params $params, $method ) {
switch ( $method ) {
case self::METHOD_UNION:
$query_method = 'get_data_query';
break;
case self::METHOD_COUNT:
$query_method = 'get_count_query';
break;
default:
throw new InvalidArgumentException( 'Invalid method argument: ' . $method );
}
$parts = array();
foreach ( $this->queries as $query ) {
$query_string = $query->$query_method( $params );
if ( $query_string ) {
$parts[] = $query_string;
}
}
if ( ! $parts ) {
throw new RuntimeException( 'None of subqueries matches to specified search parameters' );
}
if ( 1 === count( $parts ) ) {
return current( $parts );
}
switch ( $method ) {
case self::METHOD_UNION:
return $this->get_union( $parts );
case self::METHOD_COUNT:
return $this->get_count( $parts );
}
return null;
}
/**
* Get union
*
* @param array $parts Query parts.
*
* @return string
*/
private function get_union( array $parts ) {
return '( ' . implode( ' ) UNION ( ', $parts ) . ' )';
}
/**
* Get count
*
* @param array $parts Query parts.
*
* @return string
*/
private function get_count( array $parts ) {
return 'SELECT ( ' . implode( ' ) + ( ', $parts ) . ' )';
}
/**
* Is query valid
*
* @param mixed $query SQL query.
*
* @return bool
*/
private function is_query_valid( $query ) {
return $query instanceof Query;
}
}

View File

@@ -0,0 +1,26 @@
<?php
namespace WPML\TM\Jobs\Query;
use \WPML_TM_Jobs_Search_Params;
class LimitQueryHelper {
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return string
*/
public function get_limit( WPML_TM_Jobs_Search_Params $params ) {
$result = '';
if ( $params->get_limit() ) {
if ( $params->get_offset() ) {
$result = sprintf( 'LIMIT %d, %d', $params->get_offset(), $params->get_limit() );
} else {
$result = sprintf( 'LIMIT %d', $params->get_limit() );
}
}
return $result;
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace WPML\TM\Jobs\Query;
use \WPML_TM_Jobs_Search_Params;
class OrderQueryHelper {
public function get_order( \WPML_TM_Jobs_Search_Params $params ) {
$orders = $this->map_sort_parameters( $params );
if ( $orders ) {
return 'ORDER BY ' . implode( ', ', $orders );
} else {
return '';
}
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return array
*/
private function map_sort_parameters( WPML_TM_Jobs_Search_Params $params ) {
$orders = array();
if ( $params->get_sorting() ) {
foreach ( $params->get_sorting() as $order ) {
if ( $order->get_column() === 'language' ) {
$orders[] = 'source_language_name ' . $order->get_direction();
$orders[] = 'target_language_name ' . $order->get_direction();
} elseif ( $order->get_column() === 'sent_date' || $order->get_column() === 'deadline_date' ) {
$orders[] = "DATE({$order->get_column()}) {$order->get_direction()}";
} else {
$orders[] = $order->get_column() . ' ' . $order->get_direction();
}
}
}
return $orders;
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPML\TM\Jobs\Query;
use WPML_TM_Job_Entity;
class PackageQuery extends PostQuery {
/** @var string */
protected $title_column = 'string_packages.title';
protected function add_resource_join( QueryBuilder $query_builder ) {
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_string_packages string_packages
ON string_packages.ID = original_translations.element_id"
);
$query_builder->add_AND_where_condition( "original_translations.element_type LIKE 'package%'" );
}
protected function get_type() {
return WPML_TM_Job_Entity::PACKAGE_TYPE;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace WPML\TM\Jobs\Query;
use WPML_TM_Job_Entity;
class PostQuery extends AbstractQuery {
/**
* @param QueryBuilder $query_builder
*/
protected function add_resource_join( QueryBuilder $query_builder ) {
$query_builder->add_join( "INNER JOIN {$this->wpdb->prefix}posts posts ON posts.ID = original_translations.element_id" );
$query_builder->add_AND_where_condition( "original_translations.element_type LIKE 'post%'" );
}
protected function get_type() {
return WPML_TM_Job_Entity::POST_TYPE;
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace WPML\TM\Jobs\Query;
use \WPML_TM_Jobs_Search_Params;
interface Query {
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return string
*/
public function get_data_query( WPML_TM_Jobs_Search_Params $params );
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return int
*/
public function get_count_query( WPML_TM_Jobs_Search_Params $params );
}

View File

@@ -0,0 +1,398 @@
<?php
namespace WPML\TM\Jobs\Query;
use \wpdb;
use WPML\TM\ATE\Review\ReviewStatus;
use \WPML_TM_Jobs_Search_Params;
use \WPML_TM_Jobs_Date_Range;
use \InvalidArgumentException;
class QueryBuilder {
/** @var wpdb */
private $wpdb;
/** @var LimitQueryHelper */
protected $limit_helper;
/** @var OrderQueryHelper */
protected $order_helper;
/** @var array */
private $columns = array();
/** @var string */
private $from;
/** @var array */
private $joins = array();
/** @var array */
private $where = array();
/** @var string */
private $order;
/** @var string */
private $limit;
/**
* @param LimitQueryHelper $limit_helper
* @param OrderQueryHelper $order_helper
*/
public function __construct(
LimitQueryHelper $limit_helper,
OrderQueryHelper $order_helper
) {
global $wpdb;
$this->wpdb = $wpdb;
$this->limit_helper = $limit_helper;
$this->order_helper = $order_helper;
}
/**
* @param array $columns
*
* @return self
*/
public function set_columns( array $columns ) {
$this->columns = $columns;
return $this;
}
/**
* @param $column
*
* @return self
*/
public function add_column( $column ) {
$this->columns[] = $column;
return $this;
}
/**
* @param string $from
*
* @return self
*/
public function set_from( $from ) {
$this->from = $from;
return $this;
}
/**
* @param $join
*
* @return self
*/
public function add_join( $join ) {
$this->joins[] = $join;
return $this;
}
/**
* @param $column
* @param WPML_TM_Jobs_Search_Params $params
*
* @return self
*/
public function set_status_filter( $column, WPML_TM_Jobs_Search_Params $params ) {
if ( $params->get_status() ) {
$statuses = wpml_prepare_in( $params->get_status(), '%d' );
$this->where[] = sprintf( $column . ' IN (%s)', $statuses );
}
return $this;
}
/**
* @param string $column
* @param array|null $values
*
* @return $this
*/
public function set_multi_value_text_filter( $column, $values ) {
if ( $values ) {
$where = \wpml_collect( $values )->map(
function ( $value ) use ( $column ) {
return $this->wpdb->prepare( "{$column} LIKE %s", '%' . $value . '%' );
}
)->toArray();
$this->where[] = '( ' . implode( ' OR ', $where ) . ' )';
}
return $this;
}
/**
* @param $column
* @param WPML_TM_Jobs_Search_Params $params
*
* @return $this
*/
public function set_source_language( $column, WPML_TM_Jobs_Search_Params $params ) {
if ( $params->get_source_language() ) {
$this->where[] = $this->wpdb->prepare( "{$column} = %s", $params->get_source_language() );
}
return $this;
}
/**
* @param $column
* @param WPML_TM_Jobs_Search_Params $params
*
* @return $this
*/
public function set_target_language( $column, WPML_TM_Jobs_Search_Params $params ) {
if ( $params->get_target_language() ) {
$this->where[] = sprintf(
'%s IN (%s)',
$column,
wpml_prepare_in( $params->get_target_language() )
);
}
return $this;
}
public function set_translated_by_filter(
$local_translator_column,
$translation_service_column,
WPML_TM_Jobs_Search_Params $params
) {
if ( $params->get_scope() !== WPML_TM_Jobs_Search_Params::SCOPE_ALL && $params->get_translated_by() ) {
if ( $params->get_scope() === WPML_TM_Jobs_Search_Params::SCOPE_LOCAL ) {
$this->where[] = $this->wpdb->prepare(
"{$local_translator_column} = %d",
$params->get_translated_by()
);
} else {
$this->where[] = $this->wpdb->prepare(
"{$translation_service_column} = %d",
$params->get_translated_by()
);
}
}
return $this;
}
/**
* @param string $column
* @param int|int[] $value
*
* @return $this
*/
public function set_numeric_value_filter( $column, $value ) {
if ( $value ) {
if ( is_array( $value ) ) {
$this->where[] = sprintf( "{$column} IN(%s)", wpml_prepare_in( $value, '%d' ) );
} else {
$this->where[] = sprintf( "{$column} = %d", $value );
}
}
return $this;
}
/**
* @param $column
* @param WPML_TM_Jobs_Search_Params $params
*
* @return $this
*/
public function set_tp_id_filter( $column, WPML_TM_Jobs_Search_Params $params ) {
if ( $params->get_tp_id() ) {
$where = array();
$tp_ids = $params->get_tp_id();
if ( in_array( null, $tp_ids, true ) ) {
$tp_ids = array_filter( $tp_ids );
$where[] = $column . ' IS NULL';
}
if ( $tp_ids ) {
$where[] = sprintf( $column . ' IN (%s)', wpml_prepare_in( $tp_ids ) );
}
$this->where[] = '( ' . implode( ' OR ', $where ) . ' )';
}
return $this;
}
/**
* @param string $column
* @param WPML_TM_Jobs_Date_Range $date_range
*
* @return self
*/
public function set_date_range( $column, WPML_TM_Jobs_Date_Range $date_range ) {
$sql_parts = array();
if ( $date_range->get_begin() ) {
$sql_parts[] = $this->wpdb->prepare( $column . ' >= %s', $date_range->get_begin()->format( 'Y-m-d' ) );
}
if ( $date_range->get_end() ) {
$sql_parts[] = $this->wpdb->prepare(
$column . ' <= %s',
$date_range->get_end()->format( 'Y-m-d 23:59:59' )
);
}
if ( $sql_parts ) {
$sql = '( ' . implode( ' AND ', $sql_parts ) . ' )';
if ( $date_range->is_include_null_date() ) {
$sql .= " OR $column IS NULL";
$sql = "( $sql )";
}
$this->where[] = $sql;
}
return $this;
}
public function set_needs_review() {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translation_status.review_status = %s OR translation_status.review_status = %s)',
ReviewStatus::NEEDS_REVIEW,
ReviewStatus::EDITING
)
);
}
public function set_do_not_need_review() {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translation_status.review_status IS NULL OR translation_status.review_status = %s)',
ReviewStatus::ACCEPTED
)
);
}
public function set_max_retries( $maxRetries ) {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translation_status.ate_comm_retry_count <= %d )',
$maxRetries
)
);
}
public function set_element_type( $element_type ) {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translations.element_type = %s )',
$element_type
)
);
}
/**
* @param bool $automatic
*/
public function set_automatic( $automatic = true ) {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translate_job.automatic = %d )',
$automatic ? 1 : 0
)
);
}
/**
* @param int $maxAteSyncCount
*/
public function set_max_ate_sync_count( $maxAteSyncCount ) {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'(translate_job.ate_sync_count <= %d )',
$maxAteSyncCount
)
);
}
public function set_set_excluded_jobs() {
$this->add_AND_where_condition(
$this->wpdb->prepare(
'translation_status.status != %s',
\WPML_TM_ATE_API::SHOULD_HIDE_STATUS
)
);
}
/**
* @param string $where
*
* @return self
*/
public function add_AND_where_condition( $where ) {
$this->where[] = $where;
return $this;
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return self
*/
public function set_order( WPML_TM_Jobs_Search_Params $params ) {
$this->order = $this->order_helper->get_order( $params );
return $this;
}
/**
* @param WPML_TM_Jobs_Search_Params $params
*
* @return self
*/
public function set_limit( WPML_TM_Jobs_Search_Params $params ) {
$this->limit = $this->limit_helper->get_limit( $params );
return $this;
}
public function build() {
if ( ! $this->columns ) {
throw new InvalidArgumentException( 'You have to specify columns list' );
}
if ( ! $this->from ) {
throw new InvalidArgumentException( 'You have to specify FROM table' );
}
$sql = '
SELECT
%s
FROM %s
';
$sql = sprintf( $sql, implode( ', ', $this->columns ), $this->from );
if ( $this->joins ) {
$sql .= implode( ' ', $this->joins );
}
if ( $this->where ) {
$sql .= ' WHERE ' . implode( ' AND ', $this->where );
}
if ( $this->order ) {
$sql .= ' ' . $this->order;
}
if ( $this->limit ) {
$sql .= ' ' . $this->limit;
}
return $sql;
}
}

View File

@@ -0,0 +1,232 @@
<?php
/**
* WPML_TM_Jobs_String_Query class file
*
* @package wpml-translation-management
*/
namespace WPML\TM\Jobs\Query;
use \wpdb;
use \WPML_TM_Jobs_Search_Params;
use \WPML_TM_Job_Entity;
class StringQuery implements Query {
/**
* WP database instance
*
* @var wpdb
*/
protected $wpdb;
/**
* Query builder instance
*
* @var QueryBuilder
*/
protected $query_builder;
/** @var string */
protected $batch_name_column = 'batches.batch_name';
/**
* @param wpdb $wpdb WP database instance.
* @param QueryBuilder $query_builder Query builder instance.
*/
public function __construct( wpdb $wpdb, QueryBuilder $query_builder ) {
$this->wpdb = $wpdb;
$this->query_builder = $query_builder;
}
/**
* Get data query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @return string
*/
public function get_data_query( WPML_TM_Jobs_Search_Params $params ) {
$columns = array(
'string_translations.id as id',
'"' . WPML_TM_Job_Entity::STRING_TYPE . '" as type',
'string_status.rid as tp_id',
'batches.id as local_batch_id',
'batches.tp_id as tp_batch_id',
$this->batch_name_column,
'string_translations.status as status',
'strings.id as original_element_id',
'strings.language as source_language',
'string_translations.language as target_language',
'string_translations.translation_service as translation_service',
'string_status.timestamp as sent_date',
'NULL as deadline_date',
'NULL as completed_date',
'strings.value as title',
'source_languages.english_name as source_language_name',
'target_languages.english_name as target_language_name',
'string_translations.translator_id as translator_id',
'NULL as translate_job_id',
'core_status.tp_revision AS revision',
'core_status.ts_status AS ts_status',
'NULL AS needs_update',
'NULL AS editor',
'string_translations.status = ' . ICL_TM_COMPLETE . ' AS has_completed_translation',
'NULL AS editor_job_id',
'0 AS automatic',
'NULL AS review_status',
'NULL AS trid',
'NULL AS element_type',
'NULL AS element_id',
'NULL AS job_title',
);
return $this->build_query( $params, $columns );
}
/**
* Get count query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @return int|string
*/
public function get_count_query( WPML_TM_Jobs_Search_Params $params ) {
$columns = array( 'COUNT(string_translations.id)' );
return $this->build_query( $params, $columns );
}
/**
* Build query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
* @param array $columns Database columns.
*
* @return string
*/
private function build_query( WPML_TM_Jobs_Search_Params $params, array $columns ) {
if ( $this->check_job_type( $params ) ) {
return '';
}
$query_builder = clone $this->query_builder;
$query_builder->set_columns( $columns );
$query_builder->set_from( "{$this->wpdb->prefix}icl_translation_batches AS translation_batches" );
$this->define_joins( $query_builder );
$this->define_filters( $query_builder, $params );
$query_builder->set_limit( $params );
$query_builder->set_order( $params );
return $query_builder->build();
}
/**
* Check job type.
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @return bool
*/
protected function check_job_type( WPML_TM_Jobs_Search_Params $params ) {
return $params->get_job_types() && ! in_array( WPML_TM_Job_Entity::STRING_TYPE, $params->get_job_types(), true );
}
/**
* Define joins
*
* @param QueryBuilder $query_builder Query builder instance.
*/
private function define_joins( QueryBuilder $query_builder ) {
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_string_translations AS string_translations
ON string_translations.batch_id = translation_batches.id"
);
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_strings AS strings
ON strings.id = string_translations.string_id"
);
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_string_status AS string_status
ON string_status.string_translation_id = string_translations.id"
);
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_core_status AS core_status
ON core_status.rid = string_status.rid"
);
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_languages source_languages
ON source_languages.code = strings.language"
);
$query_builder->add_join(
"LEFT JOIN {$this->wpdb->prefix}icl_languages target_languages
ON target_languages.code = string_translations.language"
);
$query_builder->add_join(
"INNER JOIN {$this->wpdb->prefix}icl_translation_batches batches
ON batches.id = string_translations.batch_id"
);
}
/**
* Define filters
*
* @param QueryBuilder $query_builder Query builder instance.
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*/
private function define_filters( QueryBuilder $query_builder, WPML_TM_Jobs_Search_Params $params ) {
$query_builder->set_status_filter( 'string_translations.status', $params );
$query_builder = $this->set_scope_filter( $query_builder, $params );
$query_builder->set_multi_value_text_filter( 'strings.value', $params->get_title() );
$query_builder->set_multi_value_text_filter( $this->batch_name_column, $params->get_batch_name() );
$query_builder->set_source_language( 'strings.language', $params );
$query_builder->set_target_language( 'string_translations.language', $params );
$query_builder->set_translated_by_filter(
'string_translations.translator_id',
'string_translations.translation_service',
$params
);
if ( $params->get_sent() ) {
$query_builder->set_date_range( 'string_status.timestamp', $params->get_sent() );
}
$query_builder->set_numeric_value_filter( 'string_translations.id', $params->get_first_local_job_id() );
$query_builder->set_numeric_value_filter( 'strings.id', $params->get_original_element_id() );
$query_builder->set_tp_id_filter( 'string_status.rid', $params );
if ( $params->get_deadline() ) {
$query_builder->add_AND_where_condition( '1 = 0' );
}
}
private function set_scope_filter( QueryBuilder $query_builder, WPML_TM_Jobs_Search_Params $params ) {
switch ( $params->get_scope() ) {
case WPML_TM_Jobs_Search_Params::SCOPE_LOCAL:
$query_builder->add_AND_where_condition( 'string_status.rid IS NULL' );
break;
case WPML_TM_Jobs_Search_Params::SCOPE_REMOTE:
$query_builder->add_AND_where_condition( 'string_status.rid IS NOT NULL' );
break;
case WPML_TM_Jobs_Search_Params::SCOPE_ATE:
/*
This class serves the old fashioned string jobs which did not support ATE.
Due to that, it should return nothing when ATE Scope is set.
*/
$query_builder->add_AND_where_condition( '1 <> 1' );
break;
}
return $query_builder;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace WPML\TM\Jobs\Query;
use WPML_TM_Job_Entity;
class StringsBatchQuery extends AbstractQuery {
/** @var string */
protected $title_column = 'translation_batches.batch_name';
protected function add_resource_join( QueryBuilder $query_builder ) {
$query_builder->add_join( "INNER JOIN {$this->wpdb->prefix}icl_translation_batches translation_batches ON translation_batches.id = original_translations.element_id" );
$query_builder->add_AND_where_condition( "original_translations.element_type = 'st-batch_strings'" );
}
protected function get_type() {
return WPML_TM_Job_Entity::STRING_BATCH;
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace WPML\TM\Jobs\Utils;
use WPML\TM\Menu\PostLinkUrl;
use WPML_Post_Translation;
class ElementLink {
/** @var PostLinkUrl $postLinkUrl */
private $postLinkUrl;
/** @var WPML_Post_Translation $postTranslation */
private $postTranslation;
public function __construct( PostLinkUrl $postLinkUrl, WPML_Post_Translation $postTranslation ) {
$this->postLinkUrl = $postLinkUrl;
$this->postTranslation = $postTranslation;
}
public function getOriginal( \WPML_TM_Post_Job_Entity $job ) {
return $this->get( $job, $job->get_original_element_id() );
}
/**
* @param \WPML_TM_Post_Job_Entity $job
*
* @return string
*/
public function getTranslation( \WPML_TM_Post_Job_Entity $job ) {
if ( $this->isExternalType( $job->get_element_type_prefix() ) ) {
return '';
}
$translatedId = $this->postTranslation->element_id_in( $job->get_original_element_id(), $job->get_target_language() );
if ( $translatedId ) {
return $this->get( $job, $translatedId );
}
return '';
}
/**
* @param \WPML_TM_Post_Job_Entity $job
* @param string|null $elementId
*
* @return mixed|string|void
*/
private function get( \WPML_TM_Post_Job_Entity $job, $elementId = null ) {
$elementId = $elementId ?: $job->get_target_language();
$elementType = preg_replace( '/^' . $job->get_element_type_prefix() . '_/', '', $job->get_element_type() );
if ( $this->isExternalType( $job->get_element_type_prefix() ) ) {
$tmPostLink = apply_filters( 'wpml_external_item_url', '', $elementId );
} else {
$tmPostLink = $this->postLinkUrl->viewLinkUrl( $elementId );
}
$tmPostLink = apply_filters(
'wpml_document_view_item_link',
$tmPostLink,
'',
$job,
$job->get_element_type_prefix(),
$elementType
);
return $tmPostLink;
}
/**
* @param string $elementTypePrefix
*
* @return bool
*/
private function isExternalType( $elementTypePrefix ) {
return apply_filters( 'wpml_is_external', false, $elementTypePrefix );
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace WPML\TM\Jobs\Utils;
use function WPML\Container\make;
use WPML_Post_Translation;
class ElementLinkFactory {
public static function create() {
/**
* @var WPML_Post_Translation $wpml_post_translations;
*/
global $wpml_post_translations;
return make(
ElementLink::class,
[ ':postTranslation' => $wpml_post_translations ]
);
}
}