Skip to content

Commit

Permalink
Proxy command: skip tables #142 (#143)
Browse files Browse the repository at this point in the history
* Proxy command: skip tables #142

* Proxy command: skip tables #142

* Unit test for ClientBuild #142
  • Loading branch information
boehsermoe authored and nadar committed May 31, 2018
1 parent 01ac734 commit b6fb892
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 41 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. This projec
+ [#128](https://github.com/luyadev/luya-module-admin/issues/128) A new indicator display the amount of time left until the user is logged out automatically. Also every keystroke inside any text field will reset the logout timer to null. No more timeouts while working!
+ [#126](https://github.com/luyadev/luya-module-admin/issues/126) Provide option to eager load api model relations.
+ [#20](https://github.com/luyadev/luya-module-admin/issues/20) New option `--sync-requests-count` for proxy command.
+ [#142](https://github.com/luyadev/luya-module-admin/issues/142) Proxy command can skip tables with `!` negation.
+ [#144](https://github.com/luyadev/luya-module-admin/pull/144) Proxy command ask for large table sync.

### Fixed
Expand Down
51 changes: 26 additions & 25 deletions src/commands/ProxyController.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,32 +68,33 @@
class ProxyController extends Command
{
use CacheableTrait;

const CONFIG_VAR_URL = 'lcpProxyUrl';

const CONFIG_VAR_TOKEN = 'lcpProxyToken';

const CONFIG_VAR_IDENTIFIER = 'lcpProxyIdentifier';

/**
* @inheritdoc
*/
public $defaultAction = 'sync';

/**
* @var boolean Whether the isComplet sync check should be done after finish or not. If a table has a lot of traffic sometimes
* there is a difference between the exchange of table informations (build) and transfer the data. In order to prevent
* the exception message you can disable the strict compare mode. In order to ensure strict comparing enable $strict.
*/
public $strict = false;

/**
* @var string If a table option is passed only this table will be synchronised. If false by default all tables will be synced. You
* can define multible tables ab seperating those with a comma `table1,table2,table`. In order to define only tables with start
* with a given prefix you can use `app_*` using asterisks symbold to define wild card starts with string defintions.
* To exclude tables you can use a `!` before the tablename e.g. `!admin_*` or multible `!admin_*,!test_*`
*/
public $table;

/**
* @var string The production environment Domain where your LUYA application is running in production mode make so to use the right protocolo
* examples:
Expand All @@ -102,7 +103,7 @@ class ProxyController extends Command
*
*/
public $url;

/**
* @var string The identifier you get from the Machines menu in your production env admin looks like this: lcp58e35acb4ca69
*/
Expand All @@ -117,23 +118,23 @@ class ProxyController extends Command
* @var integer Number of requests collected until they are written to the database.
*/
public $syncRequestsCount = 10;

/**
* @inheritdoc
*/
public function options($actionID)
{
return array_merge(parent::options($actionID), ['strict', 'table', 'url', 'idf', 'token', 'syncRequestsCount']);
}

/**
* @inheritdoc
*/
public function optionAliases()
{
return array_merge(parent::optionAliases(), ['s' => 'strict', 't' => 'table', 'u' => 'url', 'i' => 'idf', 'tk' => 'token']);
}

/**
* Sync Proxy Data.
*
Expand All @@ -143,47 +144,47 @@ public function actionSync()
{
if ($this->url === null) {
$url = Config::get(self::CONFIG_VAR_URL);

if (!$url) {
$url = $this->prompt('Enter the Proxy PROD env URL (e.g. https://example.com):');
Config::set(self::CONFIG_VAR_URL, $url);
}
} else {
$url = $this->url;
}

if ($this->idf === null) {
$identifier = Config::get(self::CONFIG_VAR_IDENTIFIER);

if (!$identifier) {
$identifier = $this->prompt('Please enter the identifier:');
Config::set(self::CONFIG_VAR_IDENTIFIER, trim($identifier));
}
} else {
$identifier = $this->idf;
}

if ($this->token === null) {
$token = Config::get(self::CONFIG_VAR_TOKEN);

if (!$token) {
$token = $this->prompt('Please enter the access token:');
Config::set(self::CONFIG_VAR_TOKEN, trim($token));
}
} else {
$token = $this->token;
}


$proxyUrl = Url::ensureHttp(rtrim(trim($url), '/')) . '/admin/api-admin-proxy';
$this->outputInfo('Connect to: ' . $proxyUrl);

$curl = new Curl();
$curl->get($proxyUrl, ['identifier' => $identifier, 'token' => sha1($token)]);

if (!$curl->error) {
$this->flushHasCache();

$this->verbosePrint($curl->response);
$response = Json::decode($curl->response);
$build = new ClientBuild($this, [
Expand All @@ -199,18 +200,18 @@ public function actionSync()
'machineIdentifier' => $identifier,
'machineToken' => sha1($token),
]);

$process = new ClientTransfer(['build' => $build]);
if ($process->start()) {
// as the admin_config table is synced to, we have to restore the current active config which has been used.
Config::set(self::CONFIG_VAR_IDENTIFIER, $identifier);
Config::set(self::CONFIG_VAR_TOKEN, $token);
Config::set(self::CONFIG_VAR_URL, $url);

return $this->outputSuccess('Sync process has been successfully finished.');
}
}

$this->clearConfig();
$this->output($curl->response);
return $this->outputError($curl->error_message);
Expand All @@ -222,7 +223,7 @@ private function clearConfig()
Config::remove(self::CONFIG_VAR_URL);
Config::remove(self::CONFIG_VAR_IDENTIFIER);
}

/**
* Cleanup all stored Config Data.
*
Expand Down
67 changes: 51 additions & 16 deletions src/proxy/ClientBuild.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,41 +71,76 @@ public function init()
}

private $_buildConfig;

public function setBuildConfig(array $config)
{
$this->_buildConfig = $config;

foreach ($config['tables'] as $tableName => $tableConfig) {
if (!empty($this->optionTable)) {
$skip = true;

foreach ($this->optionTable as $useName) {
if ($useName == $tableName || StringHelper::startsWithWildcard($tableName, $useName)) {
$skip = false;
}
}

if ($skip) {

if ($this->isSkippableTable($tableName, $this->optionTable)) {
continue;
}
}

$schema = Yii::$app->db->getTableSchema($tableName);

if ($schema !== null) {
$this->_tables[$tableName] = new ClientTable($this, $tableConfig);
}
}
}


/**
* Compare the tableName with the given filters.
*
* Example filters:
*
* "cms_*" include only cms_* tables
* "cms_*,admin_*" include only cms_* and admin_* tables
* "!cms_*" exclude all cms_* tables
* "!cms_*,!admin_*" exclude all cms_*and admin_* tables
* "cms_*,!admin_*" include all cms_* tables but exclude all admin_* tables
*
* Only first match is relevant:
* "cms_*,!admin_*,admin_*" include all cms_* tables but exclude all admin_* tables (last match has no effect)
* "cms_*,admin_*,!admin_*" include all cms_* and admin_* tables (last match has no effect)
*
* @param $tableName
* @param array $filters Array of tables which should skipped.
* @return bool True if table can be skipped.
* @since 1.2.1
*/
private function isSkippableTable($tableName, array $filters)
{
$skip = true;

foreach ($filters as $filter) {

$exclude = false;
if (substr($filter, 0, 1) == "!") {
$exclude = true;
$skip = false;

$filter = substr($filter, 1);
}

if ($filter == $tableName || StringHelper::startsWithWildcard($tableName, $filter)) {
return $exclude;
}
}

return $skip;
}

public function getStorageFilesCount()
{
return $this->_buildConfig['storageFilesCount'];
}

private $_tables = [];

public function getTables()
{
return $this->_tables;
Expand Down
62 changes: 62 additions & 0 deletions tests/admin/proxy/ClientBuildTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

namespace admintests\admin\proxy;

use admintests\AdminTestCase;
use luya\admin\proxy\ClientBuild;
use luya\admin\commands\ProxyController;

class ClientBuildTest extends AdminTestCase
{
public function testIsSkippableTable()
{
$ctrl = new ProxyController('proxyctrl', $this->app);
$build = new ClientBuild($ctrl, [
'buildConfig' => ['tables' => []],
]);

$tableFilters = [
"cms_include_case1" => ["cms_*"],
"cms_include_case2" => ["!admin_*"],

"cms_include_case3" => ["cms_*", "admin_*"],
"admin_include_case3" => ["cms_*", "admin_*"],

"cms_include_case4" => ["cms_*", "admin_*"],
"admin_include_case4" => ["cms_*", "admin_*"],

"cms_include_case5" => ["cms_*", "admin_*", "!cms_*"],
"admin_include_case5" => ["cms_*", "admin_*", "!cms_*"],
];

foreach ($tableFilters as $tableName => $filters) {
$this->assertFalse($this->invokeMethod($build, 'isSkippableTable', [$tableName, $filters]), "$tableName should be skippable by filter " . implode(', ', $filters));
}
}

public function testIsNotSkippableTable()
{
$ctrl = new ProxyController('proxyctrl', $this->app);
$build = new ClientBuild($ctrl, [
'buildConfig' => ['tables' => []],
]);

$tableFilters = [
"cms_exclude_case1" => ["!cms_*"],
"cms_exclude_case2" => ["admin_*"],

"cms_exclude_case3" => ["!cms_*", "!admin_*"],
"admin_exclude_case3" => ["!cms_*", "!admin_*"],

"cms_exclude_case4" => ["!cms_*", "!admin_*"],
"admin_exclude_case4" => ["!cms_*", "!admin_*"],

"cms_exclude_case5" => ["!cms_*", "!admin_*", "cms_*"],
"admin_exclude_case5" => ["!cms_*", "!admin_*", "cms_*"],
];

foreach ($tableFilters as $tableName => $filters) {
$this->assertTrue($this->invokeMethod($build, 'isSkippableTable', [$tableName, $filters]), "$tableName should not be skippable by filter " . implode(', ', $filters));
}
}
}

0 comments on commit b6fb892

Please sign in to comment.