tmgmt.entity.job.inc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. <?php
  2. /*
  3. * @file
  4. * Contains job entity class.
  5. */
  6. /**
  7. * Entity class for the tmgmt_job entity.
  8. *
  9. * @ingroup tmgmt_job
  10. */
  11. class TMGMTJob extends Entity {
  12. /**
  13. * Translation job identifier.
  14. *
  15. * @var integer
  16. */
  17. public $tjid;
  18. /**
  19. * A custom label for this job.
  20. */
  21. public $label;
  22. /**
  23. * Current state of the translation job
  24. * @var type
  25. */
  26. public $state;
  27. /**
  28. * Language to be translated from.
  29. *
  30. * @var string
  31. */
  32. public $source_language;
  33. /**
  34. * Language into which the data needs to be translated.
  35. *
  36. * @var varchar
  37. */
  38. public $target_language;
  39. /**
  40. * Reference to the used translator of this job.
  41. *
  42. * @see TMGMTJob::getTranslatorController()
  43. *
  44. * @var string
  45. */
  46. public $translator;
  47. /**
  48. * Translator specific configuration and context information for this job.
  49. *
  50. * @var array
  51. */
  52. public $settings;
  53. /**
  54. * Remote identification of this job.
  55. *
  56. * @var integer
  57. */
  58. public $reference;
  59. /**
  60. * The time when the job was created as a timestamp.
  61. *
  62. * @var integer
  63. */
  64. public $created;
  65. /**
  66. * The time when the job was changed as a timestamp.
  67. *
  68. * @var integer
  69. */
  70. public $changed;
  71. /**
  72. * The user id of the creator of the job.
  73. *
  74. * @var integer
  75. */
  76. public $uid;
  77. /**
  78. * {@inheritdoc}
  79. */
  80. public function __construct(array $values = array()) {
  81. parent::__construct($values, 'tmgmt_job');
  82. if (empty($this->tjid)) {
  83. $this->created = REQUEST_TIME;
  84. }
  85. if (!isset($this->state)) {
  86. $this->state = TMGMT_JOB_STATE_UNPROCESSED;
  87. }
  88. }
  89. /**
  90. * Clones job as unprocessed.
  91. */
  92. public function cloneAsUnprocessed() {
  93. $clone = clone $this;
  94. $clone->tjid = NULL;
  95. $clone->uid = NULL;
  96. $clone->changed = NULL;
  97. $clone->reference = NULL;
  98. $clone->created = REQUEST_TIME;
  99. $clone->state = TMGMT_JOB_STATE_UNPROCESSED;
  100. return $clone;
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function defaultLabel() {
  106. // In some cases we might have a user-defined label.
  107. if (!empty($this->label)) {
  108. return $this->label;
  109. }
  110. $items = $this->getItems();
  111. $count = count($items);
  112. if ($count > 0) {
  113. $source_label = reset($items)->getSourceLabel();
  114. $t_args = array('!title' => $source_label, '!more' => $count - 1);
  115. $label = format_plural($count, '!title', '!title and !more more', $t_args);
  116. // If the label length exceeds maximum allowed then cut off exceeding
  117. // characters from the title and use it to recreate the label.
  118. if (strlen($label) > TMGMT_JOB_LABEL_MAX_LENGTH) {
  119. $max_length = strlen($source_label) - (strlen($label) - TMGMT_JOB_LABEL_MAX_LENGTH);
  120. $source_label = truncate_utf8($source_label, $max_length, TRUE);
  121. $t_args['!title'] = $source_label;
  122. $label = format_plural($count, '!title', '!title and !more more', $t_args);
  123. }
  124. }
  125. else {
  126. $wrapper = entity_metadata_wrapper($this->entityType, $this);
  127. $source = $wrapper->source_language->label();
  128. if (empty($source)) {
  129. $source = '?';
  130. }
  131. $target = $wrapper->target_language->label();
  132. if (empty($target)) {
  133. $target = '?';
  134. }
  135. $label = t('From !source to !target', array('!source' => $source, '!target' => $target));
  136. }
  137. return $label;
  138. }
  139. /**
  140. * {@inheritdoc}
  141. */
  142. public function defaultUri() {
  143. return array('path' => 'admin/tmgmt/jobs/' . $this->tjid);
  144. }
  145. /**
  146. * {@inheritdoc}
  147. */
  148. public function buildContent($view_mode = 'full', $langcode = NULL) {
  149. $content = array();
  150. if (module_exists('tmgmt_ui')) {
  151. $content = entity_ui_get_form('tmgmt_job', $this);
  152. }
  153. return entity_get_controller($this->entityType)->buildContent($this, $view_mode, $langcode, $content);
  154. }
  155. /**
  156. * Adds an item to the translation job.
  157. *
  158. * @param $plugin
  159. * The plugin name.
  160. * @param $item_type
  161. * The source item type.
  162. * @param $item_id
  163. * The source item id.
  164. *
  165. * @return TMGMTJobItem
  166. * The job item that was added to the job or FALSE if it couldn't be saved.
  167. * @throws TMGMTException
  168. * On zero item word count.
  169. */
  170. public function addItem($plugin, $item_type, $item_id) {
  171. $transaction = db_transaction();
  172. $is_new = FALSE;
  173. if (empty($this->tjid)) {
  174. $this->save();
  175. $is_new = TRUE;
  176. }
  177. $item = tmgmt_job_item_create($plugin, $item_type, $item_id, array('tjid' => $this->tjid));
  178. $item->save();
  179. if ($item->getWordCount() == 0) {
  180. $transaction->rollback();
  181. // In case we got word count 0 for the first job item, NULL tjid so that
  182. // if there is another addItem() call the rolled back job object will get
  183. // persisted.
  184. if ($is_new) {
  185. $this->tjid = NULL;
  186. }
  187. throw new TMGMTException('Job item @label (@type) has no translatable content.',
  188. array('@label' => $item->label(), '@type' => $item->getSourceType()));
  189. }
  190. return $item;
  191. }
  192. /**
  193. * Add a given TMGMTJobItem to this job.
  194. *
  195. * @param TMGMTJobItem $job
  196. * The job item to add.
  197. */
  198. function addExistingItem(TMGMTJobItem &$item) {
  199. $item->tjid = $this->tjid;
  200. $item->save();
  201. }
  202. /**
  203. * Add a log message for this job.
  204. *
  205. * @param $message
  206. * The message to store in the log. Keep $message translatable by not
  207. * concatenating dynamic values into it! Variables in the message should be
  208. * added by using placeholder strings alongside the variables argument to
  209. * declare the value of the placeholders. See t() for documentation on how
  210. * $message and $variables interact.
  211. * @param $variables
  212. * (Optional) An array of variables to replace in the message on display.
  213. * @param $type
  214. * (Optional) The type of the message. Can be one of 'status', 'error',
  215. * 'warning' or 'debug'. Messages of the type 'debug' will not get printed
  216. * to the screen.
  217. */
  218. public function addMessage($message, $variables = array(), $type = 'status') {
  219. // Save the job if it hasn't yet been saved.
  220. if (!empty($this->tjid) || $this->save()) {
  221. $message = tmgmt_message_create($message, $variables, array(
  222. 'tjid' => $this->tjid,
  223. 'type' => $type,
  224. 'uid' => $GLOBALS['user']->uid,
  225. ));
  226. if ($message->save()) {
  227. return $message;
  228. }
  229. }
  230. return FALSE;
  231. }
  232. /**
  233. * Returns all job items attached to this job.
  234. *
  235. * @param array $conditions
  236. * Additional conditions to pass into EFQ.
  237. *
  238. * @return TMGMTJobItem[]
  239. * An array of translation job items.
  240. */
  241. public function getItems($conditions = array()) {
  242. $query = new EntityFieldQuery();
  243. $query->entityCondition('entity_type', 'tmgmt_job_item');
  244. $query->propertyCondition('tjid', $this->tjid);
  245. foreach ($conditions as $key => $condition) {
  246. if (is_array($condition)) {
  247. $operator = isset($condition['operator']) ? $condition['operator'] : '=';
  248. $query->propertyCondition($key, $condition['value'], $operator);
  249. }
  250. else {
  251. $query->propertyCondition($key, $condition);
  252. }
  253. }
  254. $results = $query->execute();
  255. if (!empty($results['tmgmt_job_item'])) {
  256. return entity_load('tmgmt_job_item', array_keys($results['tmgmt_job_item']));
  257. }
  258. return array();
  259. }
  260. /**
  261. * Returns all job messages attached to this job.
  262. *
  263. * @return array
  264. * An array of translation job messages.
  265. */
  266. public function getMessages($conditions = array()) {
  267. $query = new EntityFieldQuery();
  268. $query->entityCondition('entity_type', 'tmgmt_message');
  269. $query->propertyCondition('tjid', $this->tjid);
  270. foreach ($conditions as $key => $condition) {
  271. if (is_array($condition)) {
  272. $operator = isset($condition['operator']) ? $condition['operator'] : '=';
  273. $query->propertyCondition($key, $condition['value'], $operator);
  274. }
  275. else {
  276. $query->propertyCondition($key, $condition);
  277. }
  278. }
  279. $results = $query->execute();
  280. if (!empty($results['tmgmt_message'])) {
  281. return entity_load('tmgmt_message', array_keys($results['tmgmt_message']));
  282. }
  283. return array();
  284. }
  285. /**
  286. * Returns all job messages attached to this job with timestamp newer than
  287. * $time.
  288. *
  289. * @param $time
  290. * (Optional) Messages need to have a newer timestamp than $time. Defaults
  291. * to REQUEST_TIME.
  292. *
  293. * @return array
  294. * An array of translation job messages.
  295. */
  296. public function getMessagesSince($time = NULL) {
  297. $time = isset($time) ? $time : REQUEST_TIME;
  298. $conditions = array('created' => array('value' => $time, 'operator' => '>='));
  299. return $this->getMessages($conditions);
  300. }
  301. /**
  302. * Retrieves a setting value from the job settings. Pulls the default values
  303. * (if defined) from the plugin controller.
  304. *
  305. * @param $name
  306. * The name of the setting.
  307. *
  308. * @return
  309. * The setting value or $default if the setting value is not set. Returns
  310. * NULL if the setting does not exist at all.
  311. */
  312. public function getSetting($name) {
  313. if (isset($this->settings[$name])) {
  314. return $this->settings[$name];
  315. }
  316. // The translator might provide default settings.
  317. if ($translator = $this->getTranslator()) {
  318. if (($setting = $translator->getSetting($name)) !== NULL) {
  319. return $setting;
  320. }
  321. }
  322. if ($controller = $this->getTranslatorController()) {
  323. $defaults = $controller->defaultSettings();
  324. if (isset($defaults[$name])) {
  325. return $defaults[$name];
  326. }
  327. }
  328. }
  329. /**
  330. * Returns the translator for this job.
  331. *
  332. * @return TMGMTTranslator
  333. * The translator entity or FALSE if there was a problem.
  334. */
  335. public function getTranslator() {
  336. if (isset($this->translator)) {
  337. return tmgmt_translator_load($this->translator);
  338. }
  339. return FALSE;
  340. }
  341. /**
  342. * Returns the state of the job. Can be one of the job state constants.
  343. *
  344. * @return integer
  345. * The state of the job or NULL if it hasn't been set yet.
  346. */
  347. public function getState() {
  348. // We don't need to check if the state is actually set because we always set
  349. // it in the constructor.
  350. return $this->state;
  351. }
  352. /**
  353. * Updates the state of the job.
  354. *
  355. * @param $state
  356. * The new state of the job. Has to be one of the job state constants.
  357. * @param $message
  358. * (Optional) The log message to be saved along with the state change.
  359. * @param $variables
  360. * (Optional) An array of variables to replace in the message on display.
  361. *
  362. * @return int
  363. * The updated state of the job if it could be set.
  364. *
  365. * @see TMGMTJob::addMessage()
  366. */
  367. public function setState($state, $message = NULL, $variables = array(), $type = 'debug') {
  368. // Return TRUE if the state could be set. Return FALSE otherwise.
  369. if (array_key_exists($state, tmgmt_job_states())) {
  370. $this->state = $state;
  371. $this->save();
  372. // If a message is attached to this state change add it now.
  373. if (!empty($message)) {
  374. $this->addMessage($message, $variables, $type);
  375. }
  376. }
  377. return $this->state;
  378. }
  379. /**
  380. * Checks whether the passed value matches the current state.
  381. *
  382. * @param $state
  383. * The value to check the current state against.
  384. *
  385. * @return boolean
  386. * TRUE if the passed state matches the current state, FALSE otherwise.
  387. */
  388. public function isState($state) {
  389. return $this->getState() == $state;
  390. }
  391. /**
  392. * Checks whether the user described by $account is the author of this job.
  393. *
  394. * @param $account
  395. * (Optional) A user object. Defaults to the currently logged in user.
  396. */
  397. public function isAuthor($account = NULL) {
  398. $account = isset($account) ? $account : $GLOBALS['user'];
  399. return $this->uid == $account->uid;
  400. }
  401. /**
  402. * Returns whether the state of this job is 'unprocessed'.
  403. *
  404. * @return boolean
  405. * TRUE if the state is 'unprocessed', FALSE otherwise.
  406. */
  407. public function isUnprocessed() {
  408. return $this->isState(TMGMT_JOB_STATE_UNPROCESSED);
  409. }
  410. /**
  411. * Returns whether the state of this job is 'aborted'.
  412. *
  413. * @return boolean
  414. * TRUE if the state is 'aborted', FALSE otherwise.
  415. */
  416. public function isAborted() {
  417. return $this->isState(TMGMT_JOB_STATE_ABORTED);
  418. }
  419. /**
  420. * Returns whether the state of this job is 'active'.
  421. *
  422. * @return boolean
  423. * TRUE if the state is 'active', FALSE otherwise.
  424. */
  425. public function isActive() {
  426. return $this->isState(TMGMT_JOB_STATE_ACTIVE);
  427. }
  428. /**
  429. * Returns whether the state of this job is 'rejected'.
  430. *
  431. * @return boolean
  432. * TRUE if the state is 'rejected', FALSE otherwise.
  433. */
  434. public function isRejected() {
  435. return $this->isState(TMGMT_JOB_STATE_REJECTED);
  436. }
  437. /**
  438. * Returns whether the state of this jon is 'finished'.
  439. *
  440. * @return boolean
  441. * TRUE if the state is 'finished', FALSE otherwise.
  442. */
  443. public function isFinished() {
  444. return $this->isState(TMGMT_JOB_STATE_FINISHED);
  445. }
  446. /**
  447. * Checks whether a job is translatable.
  448. *
  449. * @return boolean
  450. * TRUE if the job can be translated, FALSE otherwise.
  451. */
  452. public function isTranslatable() {
  453. if ($translator = $this->getTranslator()) {
  454. if ($translator->canTranslate($this)) {
  455. return TRUE;
  456. }
  457. }
  458. return FALSE;
  459. }
  460. /**
  461. * Checks whether a job is abortable.
  462. *
  463. * @return boolean
  464. * TRUE if the job can be aborted, FALSE otherwise.
  465. */
  466. public function isAbortable() {
  467. // Only non-submitted translation jobs can be aborted.
  468. return $this->isActive();
  469. }
  470. /**
  471. * Checks whether a job is submittable.
  472. *
  473. * @return boolean
  474. * TRUE if the job can be submitted, FALSE otherwise.
  475. */
  476. public function isSubmittable() {
  477. return $this->isUnprocessed() || $this->isRejected();
  478. }
  479. /**
  480. * Checks whether a job is deletable.
  481. *
  482. * @return boolean
  483. * TRUE if the job can be deleted, FALSE otherwise.
  484. */
  485. public function isDeletable() {
  486. return !$this->isActive();
  487. }
  488. /**
  489. * Set the state of the job to 'submitted'.
  490. *
  491. * @param $message
  492. * The log message to be saved along with the state change.
  493. * @param $variables
  494. * (Optional) An array of variables to replace in the message on display.
  495. *
  496. * @return TMGMTJob
  497. * The job entity.
  498. *
  499. * @see TMGMTJob::addMessage()
  500. */
  501. public function submitted($message = NULL, $variables = array(), $type = 'status') {
  502. if (!isset($message)) {
  503. $message = 'The translation job has been submitted.';
  504. }
  505. $this->setState(TMGMT_JOB_STATE_ACTIVE, $message, $variables, $type);
  506. }
  507. /**
  508. * Set the state of the job to 'finished'.
  509. *
  510. * @param $message
  511. * The log message to be saved along with the state change.
  512. * @param $variables
  513. * (Optional) An array of variables to replace in the message on display.
  514. *
  515. * @return TMGMTJob
  516. * The job entity.
  517. *
  518. * @see TMGMTJob::addMessage()
  519. */
  520. public function finished($message = NULL, $variables = array(), $type = 'status') {
  521. if (!isset($message)) {
  522. $message = 'The translation job has been finished.';
  523. }
  524. return $this->setState(TMGMT_JOB_STATE_FINISHED, $message, $variables, $type);
  525. }
  526. /**
  527. * Sets the state of the job to 'aborted'.
  528. *
  529. * @param $message
  530. * The log message to be saved along with the state change.
  531. * @param $variables
  532. * (Optional) An array of variables to replace in the message on display.
  533. *
  534. * Use TMGMTJob::abortTranslation() to abort a translation.
  535. *
  536. * @return TMGMTJob
  537. * The job entity.
  538. *
  539. * @see TMGMTJob::addMessage()
  540. */
  541. public function aborted($message = NULL, $variables = array(), $type = 'status') {
  542. if (!isset($message)) {
  543. $message = 'The translation job has been aborted.';
  544. }
  545. /** @var TMGMTJobItem $item */
  546. foreach ($this->getItems() as $item) {
  547. $item->setState(TMGMT_JOB_ITEM_STATE_ABORTED);
  548. }
  549. return $this->setState(TMGMT_JOB_STATE_ABORTED, $message, $variables, $type);
  550. }
  551. /**
  552. * Sets the state of the job to 'rejected'.
  553. *
  554. * @param $message
  555. * The log message to be saved along with the state change.
  556. * @param $variables
  557. * (Optional) An array of variables to replace in the message on display.
  558. *
  559. * @return TMGMTJob
  560. * The job entity.
  561. *
  562. * @see TMGMTJob::addMessage()
  563. */
  564. public function rejected($message = NULL, $variables = array(), $type = 'error') {
  565. if (!isset($message)) {
  566. $message = 'The translation job has been rejected by the translation provider.';
  567. }
  568. return $this->setState(TMGMT_JOB_STATE_REJECTED, $message, $variables, $type);
  569. }
  570. /**
  571. * Request the translation of a job from the translator.
  572. *
  573. * @return integer
  574. * The updated job status.
  575. */
  576. public function requestTranslation() {
  577. if (!$this->isTranslatable() || !$controller = $this->getTranslatorController()) {
  578. return FALSE;
  579. }
  580. // We don't know if the translator plugin already processed our
  581. // translation request after this point. That means that the plugin has to
  582. // set the 'submitted', 'needs review', etc. states on its own.
  583. $controller->requestTranslation($this);
  584. }
  585. /**
  586. * Attempts to abort the translation job. Already accepted jobs can not be
  587. * aborted, submitted jobs only if supported by the translator plugin.
  588. * Always use this method if you want to abort a translation job.
  589. *
  590. * @return boolean
  591. * TRUE if the translation job was aborted, FALSE otherwise.
  592. */
  593. public function abortTranslation() {
  594. if (!$this->isAbortable() || !$controller = $this->getTranslatorController()) {
  595. return FALSE;
  596. }
  597. // We don't know if the translator plugin was able to abort the translation
  598. // job after this point. That means that the plugin has to set the
  599. // 'aborted' state on its own.
  600. return $controller->abortTranslation($this);
  601. }
  602. /**
  603. * Returns the translator plugin controller of the translator of this job.
  604. *
  605. * @return TMGMTTranslatorPluginControllerInterface
  606. * The controller of the translator plugin.
  607. */
  608. public function getTranslatorController() {
  609. if ($translator = $this->getTranslator($this)) {
  610. return $translator->getController();
  611. }
  612. return FALSE;
  613. }
  614. /**
  615. * Returns the source data of all job items.
  616. *
  617. * @param $key
  618. * If present, only the subarray identified by key is returned.
  619. * @param $index
  620. * Optional index of an attribute below $key.
  621. * @return array
  622. * A nested array with the source data where the most upper key is the job
  623. * item id.
  624. */
  625. public function getData(array $key = array(), $index = NULL) {
  626. $data = array();
  627. if (!empty($key)) {
  628. $tjiid = array_shift($key);
  629. $item = entity_load_single('tmgmt_job_item', $tjiid);
  630. if ($item) {
  631. $data[$tjiid] = $item->getData($key, $index);
  632. // If not set, use the job item label as the data label.
  633. if (!isset($data[$tjiid]['#label'])) {
  634. $data[$tjiid]['#label'] = $item->getSourceLabel();
  635. }
  636. }
  637. }
  638. else {
  639. foreach ($this->getItems() as $tjiid => $item) {
  640. $data[$tjiid] = $item->getData();
  641. // If not set, use the job item label as the data label.
  642. if (!isset($data[$tjiid]['#label'])) {
  643. $data[$tjiid]['#label'] = $item->getSourceLabel();
  644. }
  645. }
  646. }
  647. return $data;
  648. }
  649. /**
  650. * Sums up all pending counts of this jobs job items.
  651. *
  652. * @return
  653. * The sum of all pending counts
  654. */
  655. public function getCountPending() {
  656. return tmgmt_job_statistic($this, 'count_pending');
  657. }
  658. /**
  659. * Sums up all translated counts of this jobs job items.
  660. *
  661. * @return
  662. * The sum of all translated counts
  663. */
  664. public function getCountTranslated() {
  665. return tmgmt_job_statistic($this, 'count_translated');
  666. }
  667. /**
  668. * Sums up all accepted counts of this jobs job items.
  669. *
  670. * @return
  671. * The sum of all accepted data items.
  672. */
  673. public function getCountAccepted() {
  674. return tmgmt_job_statistic($this, 'count_accepted');
  675. }
  676. /**
  677. * Sums up all accepted counts of this jobs job items.
  678. *
  679. * @return
  680. * The sum of all accepted data items.
  681. */
  682. public function getCountReviewed() {
  683. return tmgmt_job_statistic($this, 'count_reviewed');
  684. }
  685. /**
  686. * Sums up all word counts of this jobs job items.
  687. *
  688. * @return
  689. * The total word count of this job.
  690. */
  691. public function getWordCount() {
  692. return tmgmt_job_statistic($this, 'word_count');
  693. }
  694. /**
  695. * Store translated data back into the items.
  696. *
  697. * @param $data
  698. * Partially or complete translated data, the most upper key needs to be
  699. * the translation job item id.
  700. * @param $key
  701. * (Optional) Either a flattened key (a 'key1][key2][key3' string) or a nested
  702. * one, e.g. array('key1', 'key2', 'key2'). Defaults to an empty array which
  703. * means that it will replace the whole translated data array. The most
  704. * upper key entry needs to be the job id (tjiid).
  705. */
  706. public function addTranslatedData($data, $key = NULL) {
  707. $key = tmgmt_ensure_keys_array($key);
  708. $items = $this->getItems();
  709. // If there is a key, get the specific item and forward the call.
  710. if (!empty($key)) {
  711. $item_id = array_shift($key);
  712. if (isset($items[$item_id])) {
  713. $items[$item_id]->addTranslatedData($data, $key);
  714. }
  715. }
  716. else {
  717. foreach ($data as $key => $value) {
  718. if (isset($items[$key])) {
  719. $items[$key]->addTranslatedData($value);
  720. }
  721. }
  722. }
  723. }
  724. /**
  725. * Propagates the returned job item translations to the sources.
  726. *
  727. * @return boolean
  728. * TRUE if we were able to propagate the translated data, FALSE otherwise.
  729. */
  730. public function acceptTranslation() {
  731. foreach ($this->getItems() as $item) {
  732. $item->acceptTranslation();
  733. }
  734. }
  735. /**
  736. * Gets remote mappings for current job.
  737. *
  738. * @return array
  739. * List of TMGMTRemote entities.
  740. */
  741. public function getRemoteMappings() {
  742. $query = new EntityFieldQuery();
  743. $query->entityCondition('entity_type', 'tmgmt_remote');
  744. $query->propertyCondition('tjid', $this->tjid);
  745. $result = $query->execute();
  746. if (isset($result['tmgmt_remote'])) {
  747. return entity_load('tmgmt_remote', array_keys($result['tmgmt_remote']));
  748. }
  749. return array();
  750. }
  751. /**
  752. * Invoke the hook 'hook_tmgmt_source_suggestions' to get all suggestions.
  753. *
  754. * @param arary $conditions
  755. * Conditions to pass only some and not all items to the hook.
  756. *
  757. * @return array
  758. * An array with all additional translation suggestions.
  759. * - job_item: A TMGMTJobItem instance.
  760. * - referenced: A string which indicates where this suggestion comes from.
  761. * - from_job: The main TMGMTJob-ID which suggests this translation.
  762. */
  763. public function getSuggestions(array $conditions = array()) {
  764. $suggestions = module_invoke_all('tmgmt_source_suggestions', $this->getItems($conditions), $this);
  765. // Each TMGMTJob needs a job id to be able to count the words, because the
  766. // source-language is stored in the job and not the item.
  767. foreach ($suggestions as &$suggestion) {
  768. $jobItem = $suggestion['job_item'];
  769. $jobItem->tjid = $this->tjid;
  770. $jobItem->recalculateStatistics();
  771. }
  772. return $suggestions;
  773. }
  774. /**
  775. * Removes all suggestions from the given list which should not be processed.
  776. *
  777. * This function removes all suggestions from the given list which are already
  778. * assigned to a translation job or which should not be processed because
  779. * there are no words, no translation is needed, ...
  780. *
  781. * @param array &$suggestions
  782. * Associative array of translation suggestions. It must contain at least:
  783. * - tmgmt_job: An instance of a TMGMTJobItem.
  784. */
  785. public function cleanSuggestionsList(array &$suggestions) {
  786. foreach ($suggestions as $k => $suggestion) {
  787. if (is_array($suggestion) && isset($suggestion['job_item']) && ($suggestion['job_item'] instanceof TMGMTJobItem)) {
  788. $jobItem = $suggestion['job_item'];
  789. // Items with no words to translate should not be presented.
  790. if ($jobItem->getWordCount() <= 0) {
  791. unset($suggestions[$k]);
  792. continue;
  793. }
  794. // Check if there already exists a translation job for this item in the
  795. // current language.
  796. $items = tmgmt_job_item_load_all_latest($jobItem->plugin, $jobItem->item_type, $jobItem->item_id, $this->source_language);
  797. if ($items && isset($items[$this->target_language])) {
  798. unset($suggestions[$k]);
  799. continue;
  800. }
  801. } else {
  802. unset($suggestions[$k]);
  803. continue;
  804. }
  805. }
  806. }
  807. }