/
www
/
wwwroot
/
alo88.autos
/
wp-content
/
plugins
/
wp-content-crawler
/
app
/
Objects
/
Transformation
/
Base
/
Upload File
HOME
<?php /** * Created by PhpStorm. * User: turgutsaricam * Date: 16/02/2019 * Time: 18:42 * * @since 1.9.0 */ namespace WPCCrawler\Objects\Transformation\Base; use Exception; use Illuminate\Support\Str; use WPCCrawler\Objects\Informing\Informer; use WPCCrawler\Objects\Settings\SettingsImpl; use WPCCrawler\Objects\Transformation\Exceptions\TransformationFailedException; use WPCCrawler\Objects\Transformation\Objects\TransformableFieldList; use WPCCrawler\Utils; /** * Base class for a transformation service. A transformation service is a service that transforms details of a post. For * example, a translation service or a spinning service can be considered as transformation services, since they both * transform the details of a post. This class assumes a transformation service is used over an API. Hence, this class * provides the necessary backbone for registering and dealing with the APIs of transformation services. * * @package WPCCrawler\Objects\Transformation\Base * @since 1.8.1 */ abstract class AbstractTransformationService { /** * @var array<class-string<AbstractTransformAPIClient>, string> An associative array that stores transformation * service API class name as key. The value is a string that is used as a key for the transformation API. For * example, 'google_translate' can be used as key for GoogleTranslateAPIClient class. In that case, the array * should be: * [ GoogleTranslateAPIClient::class => 'google_translate' ] */ private $apiRegistry = []; /** * @var array An associative array where keys are registered transformation API keys and the values are arrays. The * value array must contain 'name' key with value being the name of the transformation API. E.g. * ['name' => 'Google Translate']. These values will be used to show the user available APIs and let * him/her select an API using a select HTML element. */ private $optionsForSelect; /** * @var string %1$s: Value returned from {@link getOptionKeyPrefix()}. E.g. 'translation'<br> * %2$s: Identifier for transformation API. E.g. 'google_translate'<br> * %3$s: Actual option key. For example, 'api_key'.<br> * An example output could be '_wpcc_translation_google_translate_api_key' */ private $optionKeyFormat = '_wpcc_%1$s_%2$s_%3$s'; /** This is a singleton */ protected function __construct() { // Initialize the options for select with a default option. $this->optionsForSelect = ['-1' => _wpcc('Select a service')]; } /** * Register an API client * * @param class-string<AbstractTransformAPIClient> $class An API client class * @param string $key A unique key for the client. It must not contain any spaces. Preferably, lowercase. * @param string $name Name for the API client. This will be shown to the user where appropriate, such as * selecting an API in a select HTML element. * @return AbstractTransformationService * @since 1.9.0 */ public function registerAPIClient(string $class, string $key, string $name): self { // If this class is already registered, do not register it again. if (isset($this->apiRegistry[$class])) return $this; $this->apiRegistry[$class] = $key; $this->optionsForSelect[$key] = [ 'name' => $name ]; return $this; } /** * Get the options that can be used in a select element that the user can select which transformation service he/she * wants to use. * * @return array */ public function getOptionsForSelect(): array { return $this->optionsForSelect; } /** * @return array<class-string<AbstractTransformAPIClient>, string> See {@link $apiRegistry} * @since 1.9.0 */ public function getAPIs(): array { return $this->apiRegistry; } /** * Get name of a transformation API client class * * @param string $apiClientKey Key of a registered transformation API client * @return string Name of the API that can be shown to the user * @since 1.9.0 */ public function getAPIName($apiClientKey) { return $this->optionsForSelect[$apiClientKey]['name']; } /** * Get key (identifier) of a previously-registered transformation API service * * @param class-string<AbstractTransformAPIClient> $transformationApiClientClass Class name of a class that extends * the class returned from * {@link getBaseAPIClientClassName()} * @return string|null The key for the API class * @since 1.9.0 */ public function getKeyFor($transformationApiClientClass) { if (!$transformationApiClientClass) return null; return Utils::array_get($this->apiRegistry, $transformationApiClientClass, null); } /** * Get transformation API client class name using its key (identifier). * * @param string|null $key The key * @return string|null Name of the class or null if there is no class for the given key. * @since 1.9.0 */ public function getClassFor($key) { if (!$key) return null; return Utils::array_get(array_flip($this->apiRegistry), $key, null); } /** * Transforms the given texts * * @param SettingsImpl $settings See {@link transformWithApiClient()} * @param array $texts See {@link transformWithApiClient()} * @param bool $dryRun See {@link transformWithApiClient()} * * @return null|array See {@link transformWithApiClient()} * @throws TransformationFailedException See {@link transformWithApiClient()} * @throws Exception See {@link createApiClientUsingSettings()} * @uses AbstractTransformationService::transformWithApiClient() * @since 1.9.0 */ public function transform(SettingsImpl $settings, $texts, $dryRun = false) { $client = $this->createApiClientUsingSettings($settings); if (!$client) return null; return $this->transformWithApiClient($client, $texts, $dryRun); } /** * Transforms the given texts using the given API client. * * @param AbstractTransformAPIClient $client See {@link applyTransformation()} * @param array $texts See {@link applyTransformation()} * @param bool $dryRun See {@link applyTransformation()} * * @return null|array See {@link applyTransformation()} * @throws TransformationFailedException See {@link applyTransformation()} * @uses AbstractTransformationService::applyTransformation() * @since 1.9.0 */ public function transformWithApiClient(AbstractTransformAPIClient $client, $texts, $dryRun = false) { $transformedTexts = $this->applyTransformation($client, $texts, $dryRun); // If the transformation is not successful, throw an exception. if(is_array($transformedTexts) && sizeof($texts) != sizeof($transformedTexts)) { throw new TransformationFailedException("WPCC - Texts could not be transformed."); } return $transformedTexts; } /** * Creates an API client instance using the settings. * * @param SettingsImpl $settings Settings that will be used to retrieve API client details such as API * key and target and source languages. These settings are the settings of * the plugin, actually. You can directly provide the plugin's settings or * the ones that are related to the transformation service. * @param string|null $serviceKey A custom service key. If this is `null`, the selected service key will * be retrieved from the provided settings. * @return null|AbstractTransformAPIClient Null or an object that is an instance of the class returned from * {@link getBaseAPIClientClassName()} * @since 1.9.0 * @throws Exception See {@link AbstractTransformAPIClient::setOptionsUsingSettings()} */ public function createApiClientUsingSettings(SettingsImpl $settings, ?string $serviceKey = null): ?AbstractTransformAPIClient { // Get the selected API service key from settings $selectedTransformationService = $serviceKey ?? $settings->getStringSetting($this->getOptionKeyForSelectedService()); // Get the class for the selected API $apiClass = $this->getClassFor($selectedTransformationService); // If there is no API class for the selected service key, notify the user and stop. if (!$apiClass) { Informer::addError(sprintf(_wpcc('Selected transformation service %1$s is not valid'), $selectedTransformationService)) ->addAsLog(); return null; } // Create an instance of the selected API client $client = new $apiClass(); // Make sure the client is valid if (!$this->validateApiClientClass($client)) return null; /** @var AbstractTransformAPIClient $client */ $client->setOptionsUsingSettings($settings); return $client; } /** * Get an option key for a transformation API client class * * @param string $optionSuffix Suffix for the key. This will be appended to the base key name. * @param class-string<AbstractTransformAPIClient> $apiClientClass Class name for a registered transformation API * client. E.g. GoogleTranslateAPIClient::class * @return string Option key For example, if the suffix is 'from' and the API client class is * GoogleTranslateAPIClient, then the created option key, assuming the API class' key is * 'google_translate', will be '_wpcc_translation_google_translate_from' * @since 1.9.0 */ public function getOptionKey($optionSuffix, $apiClientClass): string { return sprintf($this->optionKeyFormat, $this->getOptionKeyPrefix(), $this->getKeyFor($apiClientClass), $optionSuffix); } /* * PROTECTED METHODS */ /** * Checks if the given API client is an instance of the base API client class returned from * {@link getBaseAPIClientClassName()}. If not, notifies the user and adds an error log. * * @param object $client * @return bool True if the client class is valid. Otherwise, false. * @since 1.9.0 */ protected function validateApiClientClass($client): bool { if (!is_a($client, $this->getBaseAPIClientClassName())) { Informer::addError(sprintf('Class %1$s is not a %2$s. You must provide a %2$s.', get_class($client), $this->getBaseAPIClientClassName())) ->addAsLog(); return false; } return true; } /* * STATIC METHODS */ /** * Prepare transformable fields to be shown in a select HTML element. This basically prepends the given identifier * to each transformable field's key. * * @param array $transformableFields A key-value pair. For translation, this can be retrieved from * {@link Transformable::getTransformableFields()} by calling * {@link TransformableFieldList::toAssociativeArray()} * @param string $identifier An identifier that will be prepended to each key of $transformableFields * @return array<string, string> Transformable fields with the identifier prepended to their keys * @since 1.9.0 */ public static function prepareTransformableFieldForSelect(array $transformableFields, string $identifier): array { if (!$transformableFields || !$identifier) return []; // Prepare the keys of the transformable fields by prepending the identifier $options = []; foreach($transformableFields as $dotKey => $description) { $options["$identifier.$dotKey"] = $description; } return $options; } /** * Get transformable fields from the selected options for a given identifier. * * @param array $selectedOptions A sequential array where values are the selected option values. * @param string $identifier An identifier used in {@link prepareTransformableFieldForSelect()} * @since 1.9.0 * @since 1.13.0 Make static * @return array An array of prepared transformable field keys. */ public static function getTransformableFieldsFromSelect($selectedOptions, $identifier): array { if (!$selectedOptions || !$identifier) return []; $identifierLength = strlen($identifier) + 1; // +1 for "." return array_filter(array_map(function($optionValue) use (&$identifier, &$identifierLength) { return Str::startsWith($optionValue, $identifier) ? substr($optionValue, $identifierLength) : false; }, $selectedOptions)); } /* * PROTECTED ABSTRACT METHODS */ /** * @return class-string Name of the base API client class. This class is used to check if an API that is wanted to * be registered is valid or not. * @since 1.9.0 */ protected abstract function getBaseAPIClientClassName(): string; /** * @return string Prefix to be used when creating an option key for the transformation APIs. For example, for * translation, this prefix can be 'translation'. To understand how this is used, see * {@link optionKeyFormat} * @since 1.9.0 */ protected abstract function getOptionKeyPrefix(): string; /** * @return string Option key (post meta key) that stores the selected transformation service. This is basically the * name of the input field (select field) that the user interacts with to select a transformation * service. For example '_wpcc_selected_translation_service' * @since 1.9.0 */ protected abstract function getOptionKeyForSelectedService(): string; /** * Apply transformation, such as translation or spinning, to the given texts. * * @param AbstractTransformAPIClient $client The API client that will be used to transform the given texts. The * client is an instance of the class returned from * {@link getBaseAPIClientClassName()} * @param array $texts A flat array of texts, probably retrieved from * {@link ValueExtractor::fillAndFlatten()}. * @param bool $dryRun If true, the texts will not be transformed. Instead, they will be * appended dummy values to mock the transformation. * * @return null|array If the selected transformation service does not exist, returns null. Otherwise, transformed * $texts. * @throws TransformationFailedException If required parameters for the transformation service selected in the * settings are not valid, or there is a transformation error. * @since 1.9.0 */ protected abstract function applyTransformation(AbstractTransformAPIClient $client, $texts, $dryRun = false); }