Skip to content

Commit

Permalink
WIP - Add Primary Key System Interface
Browse files Browse the repository at this point in the history
  • Loading branch information
wellingguzman committed Apr 25, 2017
1 parent 95b8de5 commit ef26db7
Show file tree
Hide file tree
Showing 20 changed files with 584 additions and 150 deletions.
43 changes: 17 additions & 26 deletions api/api.php
Expand Up @@ -46,6 +46,7 @@
use Directus\Database\TableGateway\DirectusUsersTableGateway;
use Directus\Database\TableGateway\RelationalTableGateway as TableGateway;
use Directus\Database\TableSchema;
use Directus\Services\TablesService;
use Directus\Exception\ExceptionHandler;
use Directus\Mail\Mail;
use Directus\Permissions\Exception\UnauthorizedTableAlterException;
Expand Down Expand Up @@ -118,7 +119,7 @@
$app->config('debug', false);
$exceptionView = new ExceptionView();
$exceptionHandler = function (\Exception $exception) use ($app, $exceptionView) {
$app->emitter->run('application.error', [$exception]);
$app->hookEmitter->run('application.error', [$exception]);
$config = $app->container->get('config');
if (ArrayUtils::get($config, 'app.debug', true)) {
$exceptionView->exceptionHandler($app, $exception);
Expand Down Expand Up @@ -168,10 +169,10 @@
$acl = Bootstrap::get('acl');
$authentication = Bootstrap::get('auth');

$app->emitter->run('application.boot', $app);
$app->hookEmitter->run('application.boot', $app);
$app->hook('slim.before.dispatch', function () use ($app, $requestNonceProvider, $authAndNonceRouteWhitelist, $ZendDb, $acl, $authentication) {
// API/Server is about to initialize
$app->emitter->run('application.init', $app);
$app->hookEmitter->run('application.init', $app);

/** Skip routes which don't require these protections */
$routeName = $app->router()->getCurrentRoute()->getName();
Expand Down Expand Up @@ -243,8 +244,8 @@

$authentication->setLoggedUser($user['id'], true);
if ($user['id']) {
$app->emitter->run('directus.authenticated', [$app, $user]);
$app->emitter->run('directus.authenticated.token', [$app, $user]);
$app->hookEmitter->run('directus.authenticated', [$app, $user]);
$app->hookEmitter->run('directus.authenticated.token', [$app, $user]);
}

// Reload all user permissions
Expand Down Expand Up @@ -276,7 +277,7 @@

// User is authenticated
// And Directus is about to start
$app->emitter->run('directus.start', $app);
$app->hookEmitter->run('directus.start', $app);

/** Include new request nonces in the response headers */
$response = $app->response();
Expand All @@ -294,7 +295,7 @@
\Directus\Database\TableSchema::setAclInstance($permissions);
\Directus\Database\TableSchema::setConnectionInstance($ZendDb);
\Directus\Database\TableSchema::setConfig(Bootstrap::get('config'));
\Directus\Database\TableGateway\BaseTableGateway::setHookEmitter($app->container->get('emitter'));
\Directus\Database\TableGateway\BaseTableGateway::setHookEmitter($app->container->get('hookEmitter'));

$app->container->set('schemaManager', Bootstrap::get('schemaManager'));
});
Expand All @@ -307,7 +308,7 @@
}

// API/Server is about to shutdown
$app->emitter->run('application.shutdown', $app);
$app->hookEmitter->run('application.shutdown', $app);
});

/**
Expand Down Expand Up @@ -667,8 +668,8 @@
$acl->setUserId($user['id']);
$acl->setGroupId($user['group']);

$app->emitter->run('directus.authenticated', [$app, $user]);
$app->emitter->run('directus.authenticated.admin', [$app, $user]);
$app->hookEmitter->run('directus.authenticated', [$app, $user]);
$app->hookEmitter->run('directus.authenticated.admin', [$app, $user]);

$response['last_page'] = json_decode($user['last_page']);
$userSession = $authentication->getUserInfo();
Expand Down Expand Up @@ -896,27 +897,17 @@
}

if (isset($requestPayload['addTable'])) {
$isTableNameAlphanumeric = preg_match("/[a-z0-9]+/i", $requestPayload['table_name']);
$zeroOrMoreUnderscoresDashes = preg_match("/[_-]*/i", $requestPayload['table_name']);
$tableService = new TablesService($app);
ArrayUtils::remove($requestPayload, 'addTable');

if (!($isTableNameAlphanumeric && $zeroOrMoreUnderscoresDashes)) {
if ($tableService->isValidName($requestPayload['table_name'])) {
$app->response->setStatus(400);
return $app->response(['message' => __t('invalid_table_name')], ['table' => 'directus_privileges']);
}

unset($requestPayload['addTable']);

$schema = Bootstrap::get('schemaManager');
if (!$schema->tableExists($requestPayload['table_name'])) {
$app->emitter->run('table.create:before', $requestPayload['table_name']);
// Through API:
// Remove spaces and symbols from table name
// And in lowercase
$requestPayload['table_name'] = SchemaUtils::cleanTableName($requestPayload['table_name']);
$schema->createTable($requestPayload['table_name']);
$app->emitter->run('table.create', $requestPayload['table_name']);
$app->emitter->run('table.create:after', $requestPayload['table_name']);
}
$tableService->createTable($requestPayload['table_name'], ArrayUtils::get($requestPayload, 'columnsName'));

ArrayUtils::remove($requestPayload, 'columnsName');
}

$privileges = new DirectusPrivilegesTableGateway($ZendDb, $acl);
Expand Down
24 changes: 20 additions & 4 deletions api/core/Directus/Application/Application.php
Expand Up @@ -121,12 +121,28 @@ public function response()
*
* @return mixed
*/
protected function triggerFilter($name, $payload)
public function triggerFilter($name, $payload)
{
$emitter = Bootstrap::get('hookEmitter');
$payload = $emitter->apply($name, $payload);
return $this->container->get('hookEmitter')->apply($name, $payload);
}

/**
* Trigger given action name
*
* @param $name
* @param $params
*
* @return void
*/
public function triggerAction($name, $params = [])
{
if (!is_array($params)) {
$params = [$params];
}

array_unshift($params, $name);

return $payload;
call_user_func_array([$this->container->get('hookEmitter'), 'run'], $params);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions api/core/Directus/Bootstrap.php
Expand Up @@ -147,7 +147,7 @@ private static function app()
new DirectusTwigExtension()
];

$app->container->singleton('emitter', function () {
$app->container->singleton('hookEmitter', function () {
return Bootstrap::get('hookEmitter');
});

Expand Down Expand Up @@ -185,7 +185,7 @@ private static function app()
}
}

BaseTableGateway::setHookEmitter($app->container->get('emitter'));
BaseTableGateway::setHookEmitter($app->container->get('hookEmitter'));
BaseTableGateway::setContainer($app->container);

// @NOTE: Trying to separate the configuration from bootstrap, bit by bit.
Expand Down
31 changes: 28 additions & 3 deletions api/core/Directus/Database/SchemaManager.php
Expand Up @@ -111,6 +111,31 @@ public function createTable($name, $columnsName = [])
);
}

/**
* Adds a primary key to the given column
*
* @param $table
* @param $column
*
* @return bool
*/
public function addPrimaryKey($table, $column)
{
return $this->source->addPrimaryKey($table, $column);
}

/**
* Removes the primary key of the given column
*
* @param $table
* @param $column
*
* @return bool
*/
public function dropPrimaryKey($table, $column)
{
return $this->source->dropPrimaryKey($table, $column);
}

/**
* Get the table schema information
Expand Down Expand Up @@ -495,7 +520,7 @@ public function createTableObjectFromArray($data)
public function createColumnObjectFromArray($column)
{
if (!isset($column['ui'])) {
$column['ui'] = $this->getColumnDefaultUI($column['type']);
$column['ui'] = $this->getColumnDefaultInterface($column['type']);
}

$options = json_decode(ArrayUtils::get($column, 'options', ''), true);
Expand Down Expand Up @@ -555,8 +580,8 @@ protected function addColumn(Column $column)
$this->data['columns'][$tableName][$columnName] = $column;
}

public function getColumnDefaultUI($type)
public function getColumnDefaultInterface($type)
{
return $this->source->getColumnDefaultUI($type);
return $this->source->getColumnDefaultInterface($type);
}
}
38 changes: 25 additions & 13 deletions api/core/Directus/Database/Schemas/Sources/AbstractSchema.php
Expand Up @@ -93,33 +93,44 @@ public function parseRecordValuesByType(array $records, $columns)
/**
* @inheritdoc
*/
public function getColumnDefaultUI($columnType)
public function getColumnDefaultInterface($type)
{
switch ($columnType) {
$interfaceName = 'textinput';

switch ($type) {
case 'ALIAS':
return 'alias';
$interfaceName = 'alias';
break;
case 'MANYTOMANY':
case 'ONETOMANY':
return 'relational';
$interfaceName = 'relational';
break;
case 'TINYINT':
return 'checkbox';
$interfaceName = 'checkbox';
break;
case 'MEDIUMBLOB':
case 'BLOB':
return 'blob';
$interfaceName = 'blob';
break;
case 'TEXT':
case 'LONGTEXT':
return 'textarea';
$interfaceName = 'textarea';
break;
case 'CHAR':
case 'VARCHAR':
case 'POINT':
return 'textinput';
$interfaceName = 'textinput';
break;
case 'DATETIME':
case 'TIMESTAMP':
return 'datetime';
$interfaceName = 'datetime';
break;
case 'DATE':
return 'date';
$interfaceName = 'date';
break;
case 'TIME':
return 'time';
$interfaceName = 'time';
break;
case 'YEAR':
case 'INT':
case 'BIGINT':
Expand All @@ -128,9 +139,10 @@ public function getColumnDefaultUI($columnType)
case 'FLOAT':
case 'DOUBLE':
case 'DECIMAL':
return 'numeric';
$interfaceName = 'numeric';
break;
}

return 'textinput';
return $interfaceName;
}
}
67 changes: 66 additions & 1 deletion api/core/Directus/Database/Schemas/Sources/MySQLSchema.php
Expand Up @@ -11,6 +11,7 @@
namespace Directus\Database\Schemas\Sources;

use Directus\Database\Object\Column;
use Directus\Exception\Exception;
use Directus\Util\ArrayUtils;
use Zend\Db\Sql\Expression;
use Zend\Db\Sql\Predicate\In;
Expand Down Expand Up @@ -429,7 +430,7 @@ public function hasColumn($tableName, $columnName)
*/
public function getColumn($tableName, $columnName)
{
// TODO: Implement getColumn() method.
return $this->getColumns($tableName, ['column_name' => $columnName])->current();
}

/**
Expand Down Expand Up @@ -489,6 +490,70 @@ public function getColumnUI($column)
// TODO: Implement getColumnUI() method.
}

/**
* Add primary key to an existing column
*
* @param $table
* @param $column
*
* @return \Zend\Db\Adapter\Driver\StatementInterface|\Zend\Db\ResultSet\ResultSet
*
* @throws Exception
*/
public function addPrimaryKey($table, $column)
{
$columnData = $this->getColumn($table, $column);

if (!$columnData) {
// TODO: Better error message
throw new Exception('Missing column');
}

$dataType = ArrayUtils::get($columnData, 'type');

if (!$dataType) {
// TODO: Better error message
throw new Exception('Missing data type');
}

$queryFormat = 'ALTER TABLE `%s` ADD PRIMARY KEY(`%s`)';
// NOTE: Make this work with strings
if ($this->isNumericType($dataType)) {
$queryFormat .= ', MODIFY COLUMN `%s` %s AUTO_INCREMENT';
}

$query = sprintf($queryFormat, $table, $column, $column, $dataType);
$connection = $this->getConnection();

return $connection->query($query, $connection::QUERY_MODE_EXECUTE);
}

/**
* @inheritDoc
*/
public function dropPrimaryKey($table, $column)
{
$columnData = $this->getColumn($table, $column);

if (!$columnData) {
// TODO: Better message
throw new Exception('Missing column');
}

$dataType = ArrayUtils::get($columnData, 'type');

if (!$dataType) {
// TODO: Better message
throw new Exception('Missing data type');
}

$queryFormat = 'ALTER TABLE `%s` CHANGE COLUMN `%s` `%s` %s NOT NULL, DROP PRIMARY KEY';
$query = sprintf($queryFormat, $table, $column, $column, $dataType);
$connection = $this->getConnection();

return $connection->query($query, $connection::QUERY_MODE_EXECUTE);
}

/**
* Cast string values to its database type.
*
Expand Down

0 comments on commit ef26db7

Please sign in to comment.