protected function keyOp($group, $op = 'preview')
{
$errors = [];
$keymap = [];
$this->logSql = 1;
$this->sqltraces = [];
$ltm_translations = $this->manager->getTranslationsTableName();
if (!in_array($group, $this->manager->config(Manager::EXCLUDE_GROUPS_KEY)) && $this->manager->config('admin_enabled')) {
$srckeys = explode("\n", trim(\Request::get('srckeys')));
$dstkeys = explode("\n", trim(\Request::get('dstkeys')));
array_walk($srckeys, function (&$val, $key) use(&$srckeys) {
$val = trim($val);
if ($val === '') {
unset($srckeys[$key]);
}
});
array_walk($dstkeys, function (&$val, $key) use(&$dstkeys) {
$val = trim($val);
if ($val === '') {
unset($dstkeys[$key]);
}
});
if (!$group) {
$errors[] = trans($this->packagePrefix . 'messages.keyop-need-group');
} elseif (count($srckeys) !== count($dstkeys) && ($op === 'copy' || $op === 'move' || count($dstkeys))) {
$errors[] = trans($this->packagePrefix . 'messages.keyop-count-mustmatch');
} elseif (!count($srckeys)) {
$errors[] = trans($this->packagePrefix . 'messages.keyop-need-keys');
} else {
if (!count($dstkeys)) {
$dstkeys = array_fill(0, count($srckeys), null);
}
$keys = array_combine($srckeys, $dstkeys);
$hadErrors = false;
foreach ($keys as $src => $dst) {
$keyerrors = [];
if ($dst !== null) {
if ((substr($src, 0, 1) === '*') !== (substr($dst, 0, 1) === '*')) {
$keyerrors[] = trans($this->packagePrefix . 'messages.keyop-wildcard-mustmatch');
}
if ((substr($src, -1, 1) === '*') !== (substr($dst, -1, 1) === '*')) {
$keyerrors[] = trans($this->packagePrefix . 'messages.keyop-wildcard-mustmatch');
}
if (substr($src, 0, 1) === '*' && substr($src, -1, 1) === '*') {
$keyerrors[] = trans($this->packagePrefix . 'messages.keyop-wildcard-once');
}
}
if (!empty($keyerrors)) {
$hadErrors = true;
$keymap[$src] = ['errors' => $keyerrors, 'dst' => $dst];
continue;
}
list($srcgrp, $srckey) = self::keyGroup($group, $src);
list($dstgrp, $dstkey) = $dst === null ? [null, null] : self::keyGroup($group, $dst);
if (substr($src, 0, 1) === '*') {
if ($dst === null) {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, NULL dst, NULL dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
ORDER BY locale, `key`
SQL
, [$srcgrp, '%' . mb_substr($srckey, 1)]);
} else {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, CONCAT(SUBSTR(`key`, 1, CHAR_LENGTH(`key`)-?), ?) dst, ? dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
AND NOT exists(SELECT * FROM {$ltm_translations} t2 WHERE t2.value IS NOT NULL AND t2.`group` = ? AND t1.locale = t2.locale
AND t2.`key` LIKE BINARY CONCAT(SUBSTR(t1.`key`, 1, CHAR_LENGTH(t1.`key`)-?), ?))
ORDER BY locale, `key`
SQL
, [mb_strlen($srckey) - 1, mb_substr($dstkey, 1), $dstgrp, $srcgrp, '%' . mb_substr($srckey, 1), $dstgrp, mb_strlen($srckey) - 1, mb_substr($dstkey, 1)]);
}
} elseif (substr($src, -1, 1) === '*') {
if ($dst === null) {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, NULL dst, NULL dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
ORDER BY locale, `key`
SQL
, [$srcgrp, mb_substr($srckey, 0, -1) . '%']);
} else {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, CONCAT(?, SUBSTR(`key`, ?+1, CHAR_LENGTH(`key`)-?)) dst, ? dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
AND NOT exists(SELECT * FROM {$ltm_translations} t2 WHERE t2.value IS NOT NULL AND t2.`group` = ? AND t1.locale = t2.locale
AND t2.`key` LIKE BINARY CONCAT(?, SUBSTR(t1.`key`, ?+1, CHAR_LENGTH(t1.`key`)-?)))
ORDER BY locale, `key`
SQL
, [mb_substr($dstkey, 0, -1), mb_strlen($srckey) - 1, mb_strlen($srckey) - 1, $dstgrp, $srcgrp, mb_substr($srckey, 0, -1) . '%', $dstgrp, mb_substr($dstkey, 0, -1), mb_strlen($srckey) - 1, mb_strlen($srckey) - 1]);
}
} else {
if ($dst === null) {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, NULL dst, NULL dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
ORDER BY locale, `key`
SQL
, [$srcgrp, $srckey]);
} else {
$rows = $this->getConnection()->select($sql = <<<SQL
SELECT DISTINCT `group`, `key`, locale, id, ? dst, ? dstgrp FROM {$ltm_translations} t1
WHERE `group` = ? AND `key` LIKE BINARY ?
AND NOT exists(SELECT * FROM {$ltm_translations} t2 WHERE t2.value IS NOT NULL AND t2.`group` = ? AND t1.locale = t2.locale AND t2.`key` LIKE BINARY ?)
ORDER BY locale, `key`
SQL
, [$dstkey, $dstgrp, $srcgrp, $srckey, $dstgrp, $dstkey]);
}
}
$keymap[$src] = ['dst' => $dst, 'rows' => $rows];
}
if (!$hadErrors && ($op === 'copy' || $op === 'move' || $op === 'delete')) {
foreach ($keys as $src => $dst) {
$rows = $keymap[$src]['rows'];
$rowids = array_reduce($rows, function ($carry, $row) {
return $carry . ',' . $row->id;
}, '');
$rowids = substr($rowids, 1);
list($srcgrp, $srckey) = self::keyGroup($group, $src);
if ($op === 'move') {
foreach ($rows as $row) {
list($dstgrp, $dstkey) = self::keyGroup($row->dstgrp, $row->dst);
$to_delete = $this->getConnection()->select(<<<SQL
SELECT GROUP_CONCAT(id SEPARATOR ',') ids FROM {$ltm_translations} tr
WHERE `group` = ? AND `key` = ? AND locale = ? AND id NOT IN ({$rowids})
SQL
, [$dstgrp, $dstkey, $row->locale]);
if (!empty($to_delete)) {
$to_delete = $to_delete[0]->ids;
if ($to_delete) {
//$this->getConnection()->update("UPDATE ltm_translations SET is_deleted = 1 WHERE id IN ($to_delete)");
// have to delete right away, we will be bringing another key here
// TODO: copy value to new key's saved value
$this->getConnection()->delete("DELETE FROM {$ltm_translations} WHERE id IN ({$to_delete})");
}
}
$this->getConnection()->update("UPDATE {$ltm_translations} SET `group` = ?, `key` = ?, status = 1 WHERE id = ?", [$dstgrp, $dstkey, $row->id]);
}
} elseif ($op === 'delete') {
//$this->getConnection()->delete("DELETE FROM ltm_translations WHERE id IN ($rowids)");
$this->getConnection()->update("UPDATE {$ltm_translations} SET is_deleted = 1 WHERE is_deleted = 0 AND id IN ({$rowids})");
} elseif ($op === 'copy') {
// TODO: split operation into update and insert so that conflicting keys get new values instead of being replaced
foreach ($rows as $row) {
list($dstgrp, $dstkey) = self::keyGroup($row->dstgrp, $row->dst);
$to_delete = $this->getConnection()->select(<<<SQL
SELECT GROUP_CONCAT(id SEPARATOR ',') ids FROM {$ltm_translations} tr
WHERE `group` = ? AND `key` = ? AND locale = ? AND id NOT IN ({$rowids})
SQL
, [$dstgrp, $dstkey, $row->locale]);
if (!empty($to_delete)) {
$to_delete = $to_delete[0]->ids;
if ($to_delete) {
//$this->getConnection()->update("UPDATE ltm_translations SET is_deleted = 1 WHERE id IN ($to_delete)");
$this->getConnection()->delete("DELETE FROM {$ltm_translations} WHERE id IN ({$to_delete})");
}
}
$this->getConnection()->insert($sql = <<<SQL
INSERT INTO {$ltm_translations}
SELECT
NULL id,
1 status,
locale,
? `group`,
? `key`,
value,
sysdate() created_at,
sysdate() updated_at,
source,
saved_value,
is_deleted,
was_used
FROM {$ltm_translations} t1
WHERE id = ?
SQL
, [$dstgrp, $dstkey, $row->id]);
}
}
}
}
}
} else {
$errors[] = trans($this->packagePrefix . 'messages.keyops-not-authorized');
}
$this->logSql = 0;
return \View::make($this->packagePrefix . 'keyop')->with('controller', ManagerServiceProvider::CONTROLLER_PREFIX . get_class($this))->with('package', $this->package)->with('errors', $errors)->with('keymap', $keymap)->with('op', $op)->with('group', $group);
}