class Lingotek in Lingotek Translation 8.2
Same name and namespace in other branches
- 8 src/Lingotek.php \Drupal\lingotek\Lingotek
- 4.0.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.0.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.1.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.2.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.3.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.4.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.5.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.6.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.7.x src/Lingotek.php \Drupal\lingotek\Lingotek
- 3.8.x src/Lingotek.php \Drupal\lingotek\Lingotek
The connecting class between Drupal and Lingotek
Hierarchy
- class \Drupal\lingotek\Lingotek implements LingotekInterface
Expanded class hierarchy of Lingotek
69 files declare their use of Lingotek
- ConfigEntityMetadataUpdate8001Test.php in tests/
src/ Functional/ Update/ ConfigEntityMetadataUpdate8001Test.php - lingotek.batch.inc in ./
lingotek.batch.inc - Lingotek batch functions
- lingotek.module in ./
lingotek.module - Implements Drupal-related hooks for the Lingotek Translation module.
- LingotekConfigBulkProfileTest.php in tests/
src/ Functional/ LingotekConfigBulkProfileTest.php - LingotekConfigDependenciesTest.php in tests/
src/ Functional/ LingotekConfigDependenciesTest.php
1 string reference to 'Lingotek'
1 service uses Lingotek
File
- src/
Lingotek.php, line 18
Namespace
Drupal\lingotekView source
class Lingotek implements LingotekInterface {
protected static $instance;
protected $api;
/**
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* The language-locale mapper.
*
* @var \Drupal\lingotek\LanguageLocaleMapperInterface
*/
protected $languageLocaleMapper;
/**
* The Lingotek Filter manager.
*
* @var \Drupal\lingotek\LingotekFilterManagerInterface
*/
protected $lingotekFilterManager;
// Translation Status.
const STATUS_EDITED = 'EDITED';
const STATUS_IMPORTING = 'IMPORTING';
const STATUS_NONE = 'NONE';
const STATUS_REQUEST = 'REQUEST';
const STATUS_PENDING = 'PENDING';
const STATUS_INTERMEDIATE = 'INTERMEDIATE';
const STATUS_CURRENT = 'CURRENT';
const STATUS_READY = 'READY';
const STATUS_DISABLED = 'DISABLED';
const STATUS_ERROR = 'ERROR';
const STATUS_CANCELLED = 'CANCELLED';
/**
* Status untracked means the target has not been added yet.
*/
const STATUS_UNTRACKED = 'UNTRACKED';
const PROGRESS_COMPLETE = 100;
// Translation Profile.
const PROFILE_AUTOMATIC = 'automatic';
const PROFILE_MANUAL = 'manual';
const PROFILE_DISABLED = 'disabled';
const SETTINGS = 'lingotek.settings';
/**
* Constructs a Lingotek object.
*
* @param \Drupal\lingotek\Remote\LingotekApiInterface $api
* The Lingotek configuration service.
* @param \Drupal\lingotek\LanguageLocaleMapperInterface $language_locale_mapper
* The language-locale mapper.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The config factory.
* @param LingotekFilterManagerInterface $lingotek_filter_manager
* The Lingotek Filter manager.
*/
public function __construct(LingotekApiInterface $api, LanguageLocaleMapperInterface $language_locale_mapper, ConfigFactoryInterface $config_factory, LingotekFilterManagerInterface $lingotek_filter_manager) {
$this->api = $api;
$this->languageLocaleMapper = $language_locale_mapper;
$this->configFactory = $config_factory;
$this->lingotekFilterManager = $lingotek_filter_manager;
}
public static function create(ContainerInterface $container) {
if (empty(self::$instance)) {
self::$instance = new Lingotek($container
->get('lingotek.api'), $container
->get('lingotek.language_locale_mapper'), $container
->get('config.factory'), $container
->get('lingotek.filter_manager'));
}
return self::$instance;
}
public function getAccountInfo() {
try {
$response = $this->api
->getAccountInfo();
} catch (LingotekApiException $e) {
// TODO: log a warning
return FALSE;
}
if ($response) {
return json_decode($response
->getBody(), TRUE);
}
// TODO: log a warning
return FALSE;
}
public function getResources($force = FALSE) {
return [
'community' => $this
->getCommunities($force),
'project' => $this
->getProjects($force),
'vault' => $this
->getVaults($force),
'workflow' => $this
->getWorkflows($force),
'filter' => $this
->getFilters($force),
];
}
public function getDefaults() {
return $this->configFactory
->get(static::SETTINGS)
->get('default');
}
public function getCommunities($force = FALSE) {
$resources_key = 'account.resources.community';
$data = $this->configFactory
->get(static::SETTINGS)
->get($resources_key);
if (empty($data) || $force) {
$data = $this->api
->getCommunities($force);
$this->configFactory
->getEditable(static::SETTINGS)
->set($resources_key, $data)
->save();
}
return $data;
}
public function getVaults($force = FALSE) {
return $this
->getResource('account.resources.vault', 'getVaults', $force);
}
public function getProjects($force = FALSE) {
return $this
->getResource('account.resources.project', 'getProjects', $force);
}
public function getWorkflows($force = FALSE) {
return $this
->getResource('account.resources.workflow', 'getWorkflows', $force);
}
public function getProjectStatus($project_id) {
return $this->api
->getProjectStatus($project_id);
}
public function getProject($project_id) {
return $this->api
->getProject($project_id);
}
/**
* {@inheritdoc}
*/
public function getFilters($force = FALSE) {
return $this
->getResource('account.resources.filter', 'getFilters', $force);
}
public function setProjectCallBackUrl($project_id, $callback_url) {
$args = [
'format' => 'JSON',
'callback_url' => $callback_url,
];
$response = $this->api
->setProjectCallBackUrl($project_id, $args);
if ($response
->getStatusCode() == Response::HTTP_NO_CONTENT) {
return TRUE;
}
// TODO: Log item
return FALSE;
}
/**
* @deprecated
*/
public function get($key) {
return $this->configFactory
->get(static::SETTINGS)
->get($key);
}
/**
* @deprecated
*/
public function getEditable($key) {
return $this->configFactory
->getEditable(static::SETTINGS)
->get($key);
}
/**
* @deprecated
*/
public function set($key, $value) {
$this->configFactory
->getEditable(static::SETTINGS)
->set($key, $value)
->save();
}
/**
* {@inheritdoc}
*/
public function uploadDocument($title, $content, $locale, $url = NULL, LingotekProfileInterface $profile = NULL, $job_id = NULL) {
if (!is_array($content)) {
$data = json_decode($content, TRUE);
// This is the quickest way if $content is not a valid json object.
$content = $data === NULL ? $content : $data;
}
// Handle adding site defaults to the upload here, and leave
// the handling of the upload call itself to the API.
$defaults = [
'format' => 'JSON',
'project_id' => $this->configFactory
->get(static::SETTINGS)
->get('default.project'),
'fprm_id' => $this->lingotekFilterManager
->getFilterId($profile),
'fprm_subfilter_id' => $this->lingotekFilterManager
->getSubfilterId($profile),
'external_application_id' => 'e39e24c7-6c69-4126-946d-cf8fbff38ef0',
];
// Remove filters set to NULL
$defaults = array_filter($defaults);
$metadata = $this
->getIntelligenceMetadata($content);
if ($profile !== NULL && ($project = $profile
->getProject())) {
if ($project !== 'default') {
$defaults['project_id'] = $project;
}
}
if ($profile !== NULL && ($vault = $profile
->getVault())) {
if ($vault === 'default') {
$vault = $this->configFactory
->get(static::SETTINGS)
->get('default.vault');
}
$defaults['vault_id'] = $vault;
// If we use the project workflow template default vault, we omit the
// vault parameter and the TMS will decide.
if ($vault === 'project_workflow_vault') {
unset($defaults['vault_id']);
}
}
$args = array_merge($metadata, $defaults);
$args = array_merge([
'content' => json_encode($content),
'title' => $title,
'locale_code' => $locale,
], $args);
if ($url !== NULL) {
$args['external_url'] = $url;
}
if ($job_id !== NULL) {
$args['job_id'] = $job_id;
}
$response = $this->api
->addDocument($args);
$statusCode = $response
->getStatusCode();
if ($statusCode == Response::HTTP_ACCEPTED) {
$responseBody = Json::decode($response
->getBody(), TRUE);
if (!empty($responseBody) && !empty($responseBody['properties']['id'])) {
return $responseBody['properties']['id'];
}
else {
return FALSE;
}
}
elseif ($statusCode == Response::HTTP_PAYMENT_REQUIRED) {
// This is only applicable to subscription-based connectors, but the
// recommended action is to present the user with a message letting them
// know their Lingotek account has been disabled, and to please contact
// support to re-enable their account.
$responseBody = Json::decode($response
->getBody());
$message = '';
if (!empty($responseBody) && isset($responseBody['messages'])) {
$message = $responseBody['messages'][0];
}
throw new LingotekPaymentRequiredException($message);
}
else {
return FALSE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function updateDocument($doc_id, $content, $url = NULL, $title = NULL, LingotekProfileInterface $profile = NULL, $job_id = NULL) {
if (!is_array($content)) {
if ($content !== NULL) {
$data = json_decode($content, TRUE);
// This is the quickest way if $content is not a valid json object.
$content = $data === NULL ? $content : $data;
}
}
$defaults = [
'format' => 'JSON',
'fprm_id' => $this->lingotekFilterManager
->getFilterId($profile),
'fprm_subfilter_id' => $this->lingotekFilterManager
->getSubfilterId($profile),
'external_application_id' => 'e39e24c7-6c69-4126-946d-cf8fbff38ef0',
];
$metadata = $this
->getIntelligenceMetadata($content);
$args = array_merge($metadata, $defaults);
if ($url !== NULL) {
$args['external_url'] = $url;
}
if ($title !== NULL) {
$args['title'] = $title;
}
if ($job_id !== NULL) {
$args['job_id'] = $job_id;
}
if ($content !== NULL && !empty($content)) {
$args = array_merge([
'content' => json_encode($content),
], $args);
}
else {
// IF there's no content, let's remove filters, we may want to update only
// the Job ID.
unset($args['format']);
unset($args['fprm_id']);
unset($args['fprm_subfilter_id']);
unset($args['external_application_id']);
}
$response = $this->api
->patchDocument($doc_id, $args);
$statusCode = $response
->getStatusCode();
if ($statusCode == Response::HTTP_ACCEPTED) {
$responseBody = Json::decode($response
->getBody(), TRUE);
if (empty($responseBody)) {
return TRUE;
}
else {
$nextDocId = $responseBody['next_document_id'];
return $nextDocId;
}
}
elseif ($statusCode == Response::HTTP_PAYMENT_REQUIRED) {
// This is only applicable to subscription-based connectors, but the
// recommended action is to present the user with a message letting them
// know their Lingotek account has been disabled, and to please contact
// support to re-enable their account.
$responseBody = Json::decode($response
->getBody());
$message = '';
if (!empty($responseBody) && isset($responseBody['messages'])) {
$message = $responseBody['messages'][0];
}
throw new LingotekPaymentRequiredException($message);
}
elseif ($statusCode == Response::HTTP_GONE) {
// Set the status of the document back to its pre-uploaded state.
// Typically this means the state would be set to Upload, or None but this
// may vary depending on connector. Essentially, the content’s status
// indicator should show that the source content needs to be re-uploaded
// to Lingotek.
throw new LingotekDocumentArchivedException($doc_id, sprintf('Document %s has been archived.', $doc_id));
}
elseif ($statusCode == Response::HTTP_LOCKED) {
// Update the connector’s document mapping with the ID provided in the
// next_document_id within the API response. This new ID represents the
// new version of the document.
$responseBody = Json::decode($response
->getBody());
$nextDocId = '';
if (!empty($responseBody) && isset($responseBody['next_document_id'])) {
$nextDocId = $responseBody['next_document_id'];
}
throw new LingotekDocumentLockedException($doc_id, $nextDocId, sprintf('Document %s has been updated with a new version. Use document %s for all future interactions.', $doc_id, $nextDocId));
}
return FALSE;
}
/**
* Pulls the Intelligence Metadata from the Lingotek Metadata and returns it.
*
* @param array $data
* The structure of a document content.
*
* @return array
*/
public function getIntelligenceMetadata(&$data) {
$metadata = [];
if (is_array($data) && isset($data['_lingotek_metadata']['_intelligence'])) {
$metadata = $data['_lingotek_metadata']['_intelligence'];
unset($data['_lingotek_metadata']['_intelligence']);
}
return $metadata;
}
/**
* {@inheritdoc}
*/
public function deleteDocument($doc_id) {
$response = $this->api
->deleteDocument($doc_id);
$status_code = $response
->getStatusCode();
if ($status_code == Response::HTTP_NO_CONTENT || $status_code == Response::HTTP_ACCEPTED) {
return TRUE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function cancelDocument($doc_id) {
$result = FALSE;
try {
$response = $this->api
->cancelDocument($doc_id);
$status_code = $response
->getStatusCode();
if ($status_code == Response::HTTP_NO_CONTENT) {
$result = TRUE;
}
} catch (LingotekApiException $ltkException) {
if ($ltkException
->getCode() === 400) {
if (strpos($ltkException
->getMessage(), '"Unable to cancel documents which are already in a completed state. Current status: COMPLETE"') > 0) {
// We ignore errors for complete documents.
$result = TRUE;
}
}
}
return $result;
}
/**
* {@inheritdoc}
*/
public function cancelDocumentTarget($doc_id, $locale) {
$result = FALSE;
try {
$response = $this->api
->cancelDocumentTarget($doc_id, $locale);
$status_code = $response
->getStatusCode();
if ($status_code == Response::HTTP_NO_CONTENT) {
$result = TRUE;
}
} catch (LingotekApiException $ltkException) {
if ($ltkException
->getCode() === 400) {
if (strpos($ltkException
->getMessage(), '"Unable to cancel translations which are already in a completed state. Current status: COMPLETE"') > 0) {
// We ignore errors for complete documents.
$result = TRUE;
}
}
}
return $result;
}
/**
* @param $doc_id
* @return bool
*
* @deprecated in 8.x-1.4. Use ::getDocumentStatus() instead.
*/
public function documentImported($doc_id) {
return $this
->getDocumentStatus($doc_id);
}
public function addTarget($doc_id, $locale, LingotekProfileInterface $profile = NULL) {
$workflow_id = NULL;
$drupal_language = $this->languageLocaleMapper
->getConfigurableLanguageForLocale($locale);
if ($profile !== NULL && ($workflow_id = $profile
->getWorkflowForTarget($drupal_language
->getId()))) {
if ($workflow_id === 'default') {
$workflow_id = $this->configFactory
->get(static::SETTINGS)
->get('default.workflow');
}
}
$response = $this->api
->addTranslation($doc_id, $locale, $workflow_id);
$statusCode = $response
->getStatusCode();
if ($statusCode == Response::HTTP_CREATED) {
return TRUE;
}
elseif ($statusCode == Response::HTTP_PAYMENT_REQUIRED) {
// This is only applicable to subscription-based connectors, but the
// recommended action is to present the user with a message letting them
// know their Lingotek account has been disabled, and to please contact
// support to re-enable their account.
$responseBody = Json::decode($response
->getBody());
$message = '';
if (!empty($responseBody) && isset($responseBody['messages'])) {
$message = $responseBody['messages'][0];
}
throw new LingotekPaymentRequiredException($message);
}
elseif ($statusCode == Response::HTTP_GONE) {
// Set the status of the document back to its pre-uploaded state.
// Typically this means the state would be set to Upload, or None but this
// may vary depending on connector. Essentially, the content’s status
// indicator should show that the source content needs to be re-uploaded
// to Lingotek.
return FALSE;
}
elseif ($statusCode == Response::HTTP_LOCKED) {
// Update the connector’s document mapping with the ID provided in the
// next_document_id within the API response. This new ID represents the
// new version of the document.
$responseBody = Json::decode($response
->getBody());
if (empty($responseBody)) {
return FALSE;
}
else {
$nextDocId = $responseBody['next_document_id'];
return FALSE;
}
}
return FALSE;
}
public function getLocales() {
$data = $this->api
->getLocales();
$locales = [];
if ($data) {
foreach ($data['entities'] as $locale) {
$locales[] = $locale['properties']['code'];
}
}
return $locales;
}
/**
* {@inheritdoc}
*/
public function getLocalesInfo() {
$data = $this->api
->getLocales();
$locales = [];
if ($data) {
foreach ($data['entities'] as $locale) {
$languageCode = $locale['properties']['language_code'];
$countryCode = $locale['properties']['country_code'];
$title = $locale['properties']['title'];
$language = $locale['properties']['language'];
$country = $locale['properties']['country'];
$code = $locale['properties']['code'];
$locales[$code] = [
'code' => $code,
'language_code' => $languageCode,
'title' => $title,
'language' => $language,
'country_code' => $countryCode,
'country' => $country,
];
}
}
return $locales;
}
protected function getResource($resources_key, $func, $force = FALSE) {
$data = $this->configFactory
->get(static::SETTINGS)
->get($resources_key);
if (empty($data) || $force) {
$community_id = $this->configFactory
->get(static::SETTINGS)
->get('default.community');
$data = $this->api
->{$func}($community_id);
$this->configFactory
->getEditable(static::SETTINGS)
->set($resources_key, $data)
->save();
$keys = explode(".", $resources_key);
$default_key = 'default.' . end($keys);
$this
->setValidDefaultIfNotSet($default_key, $data);
}
return $data;
}
protected function setValidDefaultIfNotSet($default_key, $resources) {
$default_value = $this->configFactory
->get(static::SETTINGS)
->get($default_key);
$valid_resource_ids = array_keys($resources);
if ($default_key === 'default.filter') {
$valid_resource_ids[] = 'drupal_default';
}
if (empty($default_value) || !in_array($default_value, $valid_resource_ids)) {
$value = current($valid_resource_ids);
$this->configFactory
->getEditable(static::SETTINGS)
->set($default_key, $value)
->save();
}
}
/**
* {@inheritDoc}
*/
public function getUploadedTimestamp($doc_id) {
// For now, a passthrough to the API object so the controllers do not
// need to include that class.
$modified_date = FALSE;
try {
$response = $this->api
->getDocumentInfo($doc_id);
if ($response
->getStatusCode() == Response::HTTP_OK) {
$response_json = json_decode($response
->getBody(), TRUE);
// We have millisecond precision in Lingotek.
$modified_date = intval(floor($response_json['properties']['last_uploaded_date'] / 1000));
}
} catch (LingotekApiException $exception) {
return FALSE;
}
return $modified_date;
}
public function getDocumentStatus($doc_id) {
// For now, a passthrough to the API object so the controllers do not
// need to include that class.
try {
$response = $this->api
->getDocumentStatus($doc_id);
if ($response
->getStatusCode() == Response::HTTP_OK) {
// If an exception didn't happen, the document is succesfully imported.
// The status value there is related with translation status, so we must
// ignore it.
return TRUE;
}
} catch (LingotekApiException $exception) {
return FALSE;
}
return FALSE;
}
/**
* {@inheritdoc}
*/
public function getDocumentTranslationStatus($doc_id, $locale) {
// For now, a passthrough to the API object so the controllers do not
// need to include that class.
$response = $this->api
->getDocumentTranslationStatus($doc_id, $locale);
$progress = FALSE;
if ($response
->getStatusCode() == Response::HTTP_OK) {
$progress_json = json_decode($response
->getBody(), TRUE);
$lingotek_locale = str_replace("_", "-", $locale);
if (!empty($progress_json['entities'])) {
foreach ($progress_json['entities'] as $index => $data) {
if ($data['properties']['locale_code'] === $lingotek_locale) {
$progress = $data['properties']['percent_complete'];
if ($data['properties']['status'] === Lingotek::STATUS_CANCELLED) {
$progress = $data['properties']['status'];
}
break;
}
}
}
if ($progress === self::PROGRESS_COMPLETE) {
return TRUE;
}
}
return $progress;
}
public function getDocumentTranslationStatuses($doc_id) {
$statuses = [];
try {
$response = $this->api
->getDocumentTranslationStatuses($doc_id);
} catch (LingotekApiException $e) {
// No targets found for this doc
return $statuses;
}
if ($response
->getStatusCode() == Response::HTTP_OK) {
$progress_json = json_decode($response
->getBody(), TRUE);
if (!empty($progress_json['entities'])) {
foreach ($progress_json['entities'] as $index => $data) {
$lingotek_locale = $data['properties']['locale_code'];
$statuses[$lingotek_locale] = $data['properties']['percent_complete'];
// ToDo: We should have an structure for this, instead of treating this as an snowflake.
if ($data['properties']['status'] === Lingotek::STATUS_CANCELLED) {
$statuses[$lingotek_locale] = $data['properties']['status'];
}
}
}
}
return $statuses;
}
public function downloadDocument($doc_id, $locale) {
// For now, a passthrough to the API object so the controllers do not
// need to include that class.
$response = $this->api
->getTranslation($doc_id, $locale, $this->configFactory
->get(static::SETTINGS)
->get('preference.enable_download_source'));
$statusCode = $response
->getStatusCode();
if ($statusCode == Response::HTTP_OK) {
return json_decode($response
->getBody(), TRUE);
}
elseif ($statusCode == Response::HTTP_GONE) {
// Set the status of the document back to its pre-uploaded state.
// Typically this means the state would be set to Upload, or None but this
// may vary depending on connector. Essentially, the content’s status
// indicator should show that the source content needs to be re-uploaded
// to Lingotek.
return FALSE;
}
return FALSE;
}
public function downloadDocumentContent($doc_id) {
$response = $this->api
->getDocumentContent($doc_id);
return $response;
}
public function downloadDocuments($args = []) {
$response = $this->api
->getDocuments($args);
return $response;
}
}