first commit
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate;
|
||||
|
||||
use wpdb;
|
||||
use WPML\Collect\Support\Collection;
|
||||
use function WPML\Container\make;
|
||||
use WPML\ST\TranslationFile\Domains;
|
||||
use function wpml_collect;
|
||||
use WPML_Locale;
|
||||
|
||||
class DomainsAndLanguagesRepository {
|
||||
/** @var wpdb */
|
||||
private $wpdb;
|
||||
|
||||
/** @var Domains */
|
||||
private $domains;
|
||||
|
||||
/** @var WPML_Locale */
|
||||
private $locale;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param Domains $domains
|
||||
* @param WPML_Locale $wp_locale
|
||||
*/
|
||||
public function __construct( wpdb $wpdb, Domains $domains, WPML_Locale $wp_locale ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->domains = $domains;
|
||||
$this->locale = $wp_locale;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get() {
|
||||
return $this->getAllDomains()->map( function ( $row ) {
|
||||
return (object) [
|
||||
'domain' => $row->domain,
|
||||
'locale' => $this->locale->get_locale( $row->languageCode )
|
||||
];
|
||||
} )->values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getAllDomains() {
|
||||
$moDomains = $this->domains->getMODomains()->toArray();
|
||||
if ( ! $moDomains ) {
|
||||
return wpml_collect( [] );
|
||||
}
|
||||
|
||||
$sql = "
|
||||
SELECT DISTINCT (BINARY s.context) as `domain`, st.language as `languageCode`
|
||||
FROM {$this->wpdb->prefix}icl_string_translations st
|
||||
INNER JOIN {$this->wpdb->prefix}icl_strings s ON s.id = st.string_id
|
||||
WHERE st.`status` = 10 AND ( st.`value` != st.mo_string OR st.mo_string IS NULL)
|
||||
AND s.context IN(" . wpml_prepare_in( $moDomains ) . ")
|
||||
";
|
||||
$result = $this->wpdb->get_results( $sql );
|
||||
|
||||
return wpml_collect( $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasTranslationFilesTable() {
|
||||
return make( \WPML_Upgrade_Schema::class )->does_table_exist( 'icl_mo_files_domains' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate;
|
||||
|
||||
use WPML\ST\MO\File\Builder;
|
||||
use WPML\ST\MO\File\makeDir;
|
||||
use WPML\ST\MO\Hooks\LoadMissingMOFiles;
|
||||
use WPML\ST\TranslationFile\StringsRetrieve;
|
||||
use WPML\WP\OptionManager;
|
||||
use function WPML\Container\make;
|
||||
|
||||
class MissingMOFile {
|
||||
|
||||
use makeDir;
|
||||
const OPTION_GROUP = 'ST-MO';
|
||||
const OPTION_NAME = 'missing-mo-processed';
|
||||
|
||||
/**
|
||||
* @var Builder
|
||||
*/
|
||||
private $builder;
|
||||
/**
|
||||
* @var StringsRetrieve
|
||||
*/
|
||||
private $stringsRetrieve;
|
||||
/**
|
||||
* @var \WPML_Language_Records
|
||||
*/
|
||||
private $languageRecords;
|
||||
/**
|
||||
* @var OptionManager
|
||||
*/
|
||||
private $optionManager;
|
||||
|
||||
public function __construct(
|
||||
\WP_Filesystem_Direct $filesystem,
|
||||
Builder $builder,
|
||||
StringsRetrieveMOOriginals $stringsRetrieve,
|
||||
\WPML_Language_Records $languageRecords,
|
||||
OptionManager $optionManager
|
||||
) {
|
||||
|
||||
$this->filesystem = $filesystem;
|
||||
$this->builder = $builder;
|
||||
$this->stringsRetrieve = $stringsRetrieve;
|
||||
$this->languageRecords = $languageRecords;
|
||||
$this->optionManager = $optionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $generateMoPath
|
||||
* @param string $domain
|
||||
*/
|
||||
public function run( $generateMoPath, $domain ) {
|
||||
$processed = $this->getProcessed();
|
||||
if ( ! $processed->contains( basename( $generateMoPath ) ) && $this->maybeCreateSubdir() ) {
|
||||
$locale = make( \WPML_ST_Translations_File_Locale::class )->get( $generateMoPath, $domain );
|
||||
$strings = $this->stringsRetrieve->get(
|
||||
$domain,
|
||||
$this->languageRecords->get_language_code( $locale ),
|
||||
false
|
||||
);
|
||||
|
||||
if ( ! empty( $strings ) ) {
|
||||
$fileContents = $this->builder
|
||||
->set_language( $locale )
|
||||
->get_content( $strings );
|
||||
|
||||
$this->filesystem->put_contents( $generateMoPath, $fileContents, 0755 & ~umask() );
|
||||
}
|
||||
$processed->push( $generateMoPath );
|
||||
$this->optionManager->set( self::OPTION_GROUP, self::OPTION_NAME, $processed->toArray() );
|
||||
}
|
||||
}
|
||||
|
||||
public function isNotProcessed( $generateMoPath ) {
|
||||
return ! $this->getProcessed()->contains( basename($generateMoPath) );
|
||||
}
|
||||
|
||||
public static function getSubdir() {
|
||||
return WP_LANG_DIR . LoadMissingMOFiles::MISSING_MO_FILES_DIR;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML\Collect\Support\Collection
|
||||
*/
|
||||
private function getProcessed() {
|
||||
return wpml_collect( $this->optionManager->get( self::OPTION_GROUP, self::OPTION_NAME, [] ) )
|
||||
->map( function ( $path ) {
|
||||
return basename( $path );
|
||||
} );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\MultiSite;
|
||||
|
||||
class Condition {
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function shouldRunWithAllSites() {
|
||||
return is_multisite() && (
|
||||
$this->hasPostBodyParam()
|
||||
|| is_super_admin()
|
||||
|| defined( 'WP_CLI' )
|
||||
);
|
||||
}
|
||||
|
||||
private function hasPostBodyParam() {
|
||||
$request_body = file_get_contents( 'php://input' );
|
||||
$data = filter_var_array( (array)json_decode( $request_body ), FILTER_SANITIZE_STRING );
|
||||
|
||||
return isset( $data['runForAllSites'] ) && $data['runForAllSites'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\MultiSite;
|
||||
|
||||
|
||||
class Executor {
|
||||
|
||||
const MAIN_SITE_ID = 1;
|
||||
|
||||
/**
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return \WPML\Collect\Support\Collection
|
||||
*/
|
||||
public function withEach( $callback ) {
|
||||
$applyCallback = function( $siteId ) use ( $callback ) {
|
||||
switch_to_blog( $siteId );
|
||||
|
||||
return [ $siteId, $callback() ];
|
||||
};
|
||||
|
||||
$initialBlogId = get_current_blog_id();
|
||||
$result = $this->getSiteIds()->map( $applyCallback );
|
||||
switch_to_blog( $initialBlogId );
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML\Collect\Support\Collection
|
||||
*/
|
||||
public function getSiteIds() {
|
||||
return \wpml_collect( get_sites( [ 'number' => PHP_INT_MAX ] ) )->pluck( 'id' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $siteId
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function executeWith( $siteId, callable $callback ) {
|
||||
switch_to_blog( $siteId );
|
||||
$result = $callback();
|
||||
restore_current_blog();
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
|
||||
use WPML\Utils\Pager;
|
||||
use WPML\ST\MO\Generate\MultiSite\Executor;
|
||||
|
||||
class MultiSiteProcess implements Process {
|
||||
/** @var Executor */
|
||||
private $multiSiteExecutor;
|
||||
|
||||
/** @var SingleSiteProcess */
|
||||
private $singleSiteProcess;
|
||||
|
||||
/** @var Status */
|
||||
private $status;
|
||||
|
||||
/** @var Pager */
|
||||
private $pager;
|
||||
|
||||
/** @var SubSiteValidator */
|
||||
private $subSiteValidator;
|
||||
|
||||
/**
|
||||
* @param Executor $multiSiteExecutor
|
||||
* @param SingleSiteProcess $singleSiteProcess
|
||||
* @param Status $status
|
||||
* @param Pager $pager
|
||||
* @param SubSiteValidator $subSiteValidator
|
||||
*/
|
||||
public function __construct(
|
||||
Executor $multiSiteExecutor,
|
||||
SingleSiteProcess $singleSiteProcess,
|
||||
Status $status,
|
||||
Pager $pager,
|
||||
SubSiteValidator $subSiteValidator
|
||||
) {
|
||||
$this->multiSiteExecutor = $multiSiteExecutor;
|
||||
$this->singleSiteProcess = $singleSiteProcess;
|
||||
$this->status = $status;
|
||||
$this->pager = $pager;
|
||||
$this->subSiteValidator = $subSiteValidator;
|
||||
}
|
||||
|
||||
|
||||
public function runAll() {
|
||||
$this->multiSiteExecutor->withEach( $this->runIfSetupComplete( [ $this->singleSiteProcess, 'runAll' ] ) );
|
||||
$this->status->markComplete( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Is completed
|
||||
*/
|
||||
public function runPage() {
|
||||
$remaining = $this->pager->iterate( $this->multiSiteExecutor->getSiteIds(), function ( $siteId ) {
|
||||
return $this->multiSiteExecutor->executeWith(
|
||||
$siteId,
|
||||
$this->runIfSetupComplete( function () {
|
||||
// no more remaining pages which means that process is done
|
||||
return $this->singleSiteProcess->runPage() === 0;
|
||||
} )
|
||||
);
|
||||
} );
|
||||
|
||||
if ( $remaining === 0 ) {
|
||||
$this->multiSiteExecutor->executeWith( Executor::MAIN_SITE_ID, function () {
|
||||
$this->status->markComplete( true );
|
||||
} );
|
||||
}
|
||||
|
||||
return $remaining;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPagesCount() {
|
||||
$isCompletedForAllSites = $this->multiSiteExecutor->executeWith(
|
||||
Executor::MAIN_SITE_ID,
|
||||
[ $this->status, 'isCompleteForAllSites' ]
|
||||
);
|
||||
if ( $isCompletedForAllSites ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->multiSiteExecutor->getSiteIds()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompleted() {
|
||||
return $this->getPagesCount() === 0;
|
||||
}
|
||||
|
||||
|
||||
private function runIfSetupComplete( $callback ) {
|
||||
return function () use ( $callback ) {
|
||||
if ( $this->subSiteValidator->isValid() ) {
|
||||
return $callback();
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
|
||||
interface Process {
|
||||
|
||||
public function runAll();
|
||||
|
||||
/**
|
||||
* @return int Remaining
|
||||
*/
|
||||
public function runPage();
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getPagesCount();
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompleted();
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
use WPML\ST\MO\File\ManagerFactory;
|
||||
use WPML\ST\MO\Generate\MultiSite\Condition;
|
||||
use WPML\Utils\Pager;
|
||||
use function WPML\Container\make;
|
||||
|
||||
class ProcessFactory {
|
||||
const FILES_PAGER = 'wpml-st-mo-generate-files-pager';
|
||||
const FILES_PAGE_SIZE = 20;
|
||||
const SITES_PAGER = 'wpml-st-mo-generate-sites-pager';
|
||||
|
||||
/** @var Condition */
|
||||
private $multiSiteCondition;
|
||||
|
||||
/**
|
||||
* @param Condition $multiSiteCondition
|
||||
*/
|
||||
public function __construct( Condition $multiSiteCondition = null ) {
|
||||
$this->multiSiteCondition = $multiSiteCondition ?: new Condition();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Process
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
public function create() {
|
||||
$singleSiteProcess = self::createSingle();
|
||||
|
||||
if ( $this->multiSiteCondition->shouldRunWithAllSites() ) {
|
||||
return make( MultiSiteProcess::class,
|
||||
[ ':singleSiteProcess' => $singleSiteProcess, ':pager' => new Pager( self::SITES_PAGER, 1 ) ]
|
||||
);
|
||||
} else {
|
||||
return $singleSiteProcess;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isBackgroundProcess
|
||||
*
|
||||
* @return SingleSiteProcess
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
public static function createSingle( $isBackgroundProcess = false ) {
|
||||
return make(
|
||||
SingleSiteProcess::class,
|
||||
[
|
||||
':pager' => new Pager( self::FILES_PAGER, self::FILES_PAGE_SIZE ),
|
||||
':manager' => ManagerFactory::create(),
|
||||
':migrateAdminTexts' => \WPML_Admin_Texts::get_migrator(),
|
||||
':status' => self::createStatus( $isBackgroundProcess ),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $isBackgroundProcess
|
||||
*
|
||||
* @return mixed|\Mockery\MockInterface|Status
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
public static function createStatus( $isBackgroundProcess = false ) {
|
||||
return make( Status::class, [
|
||||
':optionPrefix' => $isBackgroundProcess ? Status::class . '_background' : null
|
||||
] );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
|
||||
use WPML\ST\MO\File\Manager;
|
||||
use WPML\ST\MO\Generate\DomainsAndLanguagesRepository;
|
||||
use WPML\Utils\Pager;
|
||||
|
||||
class SingleSiteProcess implements Process {
|
||||
|
||||
CONST TIMEOUT = 5;
|
||||
|
||||
/** @var DomainsAndLanguagesRepository */
|
||||
private $domainsAndLanguagesRepository;
|
||||
|
||||
/** @var Manager */
|
||||
private $manager;
|
||||
|
||||
/** @var Status */
|
||||
private $status;
|
||||
|
||||
/** @var Pager */
|
||||
private $pager;
|
||||
|
||||
/** @var callable */
|
||||
private $migrateAdminTexts;
|
||||
|
||||
/**
|
||||
* @param DomainsAndLanguagesRepository $domainsAndLanguagesRepository
|
||||
* @param Manager $manager
|
||||
* @param Status $status
|
||||
* @param Pager $pager
|
||||
* @param callable $migrateAdminTexts
|
||||
*/
|
||||
public function __construct(
|
||||
DomainsAndLanguagesRepository $domainsAndLanguagesRepository,
|
||||
Manager $manager,
|
||||
Status $status,
|
||||
Pager $pager,
|
||||
callable $migrateAdminTexts
|
||||
) {
|
||||
$this->domainsAndLanguagesRepository = $domainsAndLanguagesRepository;
|
||||
$this->manager = $manager;
|
||||
$this->status = $status;
|
||||
$this->pager = $pager;
|
||||
$this->migrateAdminTexts = $migrateAdminTexts;
|
||||
}
|
||||
|
||||
|
||||
public function runAll() {
|
||||
call_user_func( $this->migrateAdminTexts );
|
||||
$this->getDomainsAndLanguages()->each( function ( $row ) {
|
||||
$this->manager->add( $row->domain, $row->locale );
|
||||
} );
|
||||
|
||||
$this->status->markComplete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int Remaining
|
||||
*/
|
||||
public function runPage() {
|
||||
if ( $this->pager->getProcessedCount() === 0 ) {
|
||||
call_user_func( $this->migrateAdminTexts );
|
||||
}
|
||||
|
||||
$domains = $this->getDomainsAndLanguages();;
|
||||
$remaining = $this->pager->iterate( $domains, function ( $row ) {
|
||||
$this->manager->add( $row->domain, $row->locale );
|
||||
|
||||
return true;
|
||||
}, self::TIMEOUT );
|
||||
|
||||
if ( $remaining === 0 ) {
|
||||
$this->status->markComplete();
|
||||
}
|
||||
|
||||
return $remaining;
|
||||
}
|
||||
|
||||
public function getPagesCount() {
|
||||
if ( $this->status->isComplete() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$domains = $this->getDomainsAndLanguages();
|
||||
|
||||
if ( $domains->count() === 0 ) {
|
||||
$this->status->markComplete();
|
||||
}
|
||||
|
||||
return $domains->count();
|
||||
}
|
||||
|
||||
private function getDomainsAndLanguages() {
|
||||
return DomainsAndLanguagesRepository::hasTranslationFilesTable()
|
||||
? $this->domainsAndLanguagesRepository->get()
|
||||
: wpml_collect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompleted() {
|
||||
return $this->getPagesCount() === 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
class Status {
|
||||
/** @var \SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var string */
|
||||
private $optionPrefix;
|
||||
|
||||
/**
|
||||
* @param \SitePress $sitepress
|
||||
* @param string|null $optionPrefix
|
||||
*/
|
||||
public function __construct( \SitePress $sitepress, $optionPrefix = null ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->optionPrefix = $optionPrefix ?: self::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allSites
|
||||
*/
|
||||
public function markComplete( $allSites = false ) {
|
||||
$settings = $this->sitepress->get_setting( 'st', [] );
|
||||
$settings[ $this->getOptionName( $allSites ) ] = true;
|
||||
$this->sitepress->set_setting( 'st', $settings, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $allSites
|
||||
*/
|
||||
public function markIncomplete( $allSites = false ) {
|
||||
$settings = $this->sitepress->get_setting( 'st', [] );
|
||||
unset( $settings[ $this->getOptionName( $allSites ) ] );
|
||||
$this->sitepress->set_setting( 'st', $settings, true );
|
||||
}
|
||||
|
||||
public function markIncompleteForAll() {
|
||||
$this->markIncomplete( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isComplete() {
|
||||
$st_settings = $this->sitepress->get_setting( 'st', [] );
|
||||
|
||||
return isset( $st_settings[ $this->getOptionName( false ) ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCompleteForAllSites() {
|
||||
$st_settings = $this->sitepress->get_setting( 'st', [] );
|
||||
|
||||
return isset( $st_settings[ $this->getOptionName( true ) ] );
|
||||
}
|
||||
|
||||
private function getOptionName( $allSites ) {
|
||||
return $allSites ? $this->optionPrefix . '_has_run_all_sites' : $this->optionPrefix . '_has_run';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate\Process;
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
class SubSiteValidator {
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->is_setup_complete() && $this->hasTranslationFilesTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function hasTranslationFilesTable() {
|
||||
return make( \WPML_Upgrade_Schema::class )->does_table_exist( 'icl_mo_files_domains' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\ST\MO\Generate;
|
||||
|
||||
use WPML\ST\TranslationFile\StringsRetrieve;
|
||||
|
||||
class StringsRetrieveMOOriginals extends StringsRetrieve {
|
||||
|
||||
/**
|
||||
* @param array $row_data
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function parseTranslation( array $row_data ) {
|
||||
return ! empty( $row_data['mo_string'] ) ? $row_data['mo_string'] : null;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user