Commit e5acef07 authored by id.tarzanych's avatar id.tarzanych Committed by salvis

Issue #2495027 by id.tarzanych, salvis: Initial port to D8.

  * Developed Migrate API mapping and covered it with tests.
  * Changed 'number' column name to 'figure'.
parent 35aaf218
......@@ -4,6 +4,9 @@ CHANGELOG for ACL for Drupal 8
acl 8.x-1.x-dev:
Port to D8:
- #2495027 by id.tarzanych, salvis: Initial port to D8.
* Developed Migrate API mapping and covered it with tests.
* Changed 'number' column name to 'figure'.
acl 7.x-1.1 (2015-08-27):
......
Simply drop this module's directory into your modules directory and install via admin/build/modules.
README.txt for ACL 7.x-1.x
README.txt for ACL 8.x-1.x
......@@ -28,15 +28,15 @@ Acknowledgements
Originally written for Drupal 5 and maintained by merlinofchaos.
Ported to Drupal 6 and 7 and maintained by salvis.
Ported to Drupal 8 by id.tarzanych (Serge Skripchuk).
Upgrading from Drupal 6 or Drupal 7
-----------------------------------
Upgrading from Drupal 6
-----------------------
Update to the latest D6 release, then upgrade as outlined in the Drupal 7 docs.
Update to the latest Drupal 6/7 release, then upgrade as outlined in the
Drupal 8 Migrate docs (follow https://www.drupal.org/upgrade/migrate).
......@@ -62,7 +62,7 @@ Support/Customizations
Support by volunteers is available on
http://drupal.org/project/issues/acl?status=All&version=7.x
http://drupal.org/project/issues/acl?status=All&version=8.x
Please consider helping others as a way to give something back to the community
that provides Drupal and the contributed modules to you free of charge.
......
......@@ -5,32 +5,50 @@
* Implementations of administration functions for the acl module.
*/
use Drupal\Component\Utility\Html;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Database\Database;
/**
* Implementation of acl_edit_form().
*/
function _acl_edit_form($acl_id, $label = NULL, $new_acl = FALSE) {
$users = array();
$connection = Database::getConnection();
$accounts = array();
if (!$new_acl) {
// Ensure the ACL in question even exists.
if (!($record = db_query("SELECT name, number FROM {acl} WHERE acl_id = :acl_id", array(
if (!($record = $connection->query("SELECT name, figure FROM {acl} WHERE acl_id = :acl_id", [
'acl_id' => $acl_id,
))->fetchAssoc())) {
])->fetchAssoc())) {
return array();
}
$result = db_query("SELECT u.uid, u.name FROM {users} u LEFT JOIN {acl_user} aclu ON aclu.uid = u.uid WHERE acl_id = :acl_id", array(
'acl_id' => $acl_id));
foreach ($result as $user) {
$users[$user->uid] = $user->name;
$result = $connection->query("SELECT u.uid, ud.name FROM {users} u INNER JOIN {users_field_data} ud ON u.uid = ud.uid LEFT JOIN {acl_user} aclu ON aclu.uid = u.uid WHERE acl_id = :acl_id", [
'acl_id' => $acl_id,
]);
foreach ($result as $account) {
$accounts[$account->uid] = $account->name;
}
}
if (!isset($label)) {
$label = (isset($record['name']) ? $record['name'] : (isset($record['number']) ? $record['number'] : $acl_id));
if (isset($record['name'])) {
$label = $record['name'];
}
elseif (isset($record['figure'])) {
$label = $record['figure'];
}
else {
$label = $acl_id;
}
}
$form = array(
'#type' => 'fieldset',
'#collapsible' => TRUE,
'#title' => check_plain($label),
'#title' => Html::escape($label),
'#tree' => TRUE,
);
......@@ -42,12 +60,12 @@ function _acl_edit_form($acl_id, $label = NULL, $new_acl = FALSE) {
$form['deletions'] = array(
'#type' => 'checkboxes',
'#options' => array(),
); // placeholder
);
$form['delete_button'] = array(
'#type' => 'button',
'#name' => 'acl_' . $acl_id,
'#value' => t('Remove Checked'),
'#submit' => FALSE,
'#submit' => array(),
);
$form['add'] = array(
......@@ -61,15 +79,15 @@ function _acl_edit_form($acl_id, $label = NULL, $new_acl = FALSE) {
'#type' => 'button',
'#name' => 'acl_' . $acl_id,
'#value' => t('Add User'),
'#submit' => FALSE,
'#submit' => array(),
);
$form['user_list'] = array(
'#type' => 'hidden',
'#default_value' => serialize($users),
'#default_value' => serialize($accounts),
);
$form['#after_build'] = array('_acl_edit_form_after_build');
$form['#after_build'] = ['_acl_edit_form_after_build'];
return $form;
}
......@@ -77,26 +95,28 @@ function _acl_edit_form($acl_id, $label = NULL, $new_acl = FALSE) {
/**
* Process a form that had our buttons on it.
*/
function _acl_edit_form_after_build($form, &$form_state) {
function _acl_edit_form_after_build($form, FormStateInterface $form_state) {
// We can't use the form values because it's the entire structure
// and we have no clue where our values actually are. That's
// ok tho cause #value still works for us.
$user_list = unserialize($form['user_list']['#value']);
$button_name = 'acl_' . $form['acl_id']['#value'];
if (isset($form_state['triggering_element']) && $form_state['triggering_element']['#value'] == $form['delete_button']['#value']) {
$triggering_element = $form_state->getTriggeringElement();
if (!empty($triggering_element) && $triggering_element['#value'] == $form['delete_button']['#value']) {
$deletions = $form['deletions']['#value'];
foreach ($deletions as $uid) {
unset($user_list[$uid]);
unset($form['deletions']['#value'][$uid]);
}
}
elseif (isset($form_state['triggering_element']) && $form_state['triggering_element']['#value'] == $form['add_button']['#value'] && !empty($form['add']['#value'])) {
$user = db_query("SELECT uid, name FROM {users} WHERE name = :name", array(
elseif (!empty($triggering_element['#value']) && $triggering_element['#value'] == $form['add_button']['#value'] && !empty($form['add']['#value'])) {
$user = Database::getConnection()->query("SELECT u.uid, ud.name FROM {users} u INNER JOIN {users_field_data} ud ON u.uid = ud.uid WHERE ud.name = :name", [
'name' => $form['add']['#value'],
))->fetchObject();
])->fetchObject();
if (!$user) {
form_error($form['add'], t("Invalid user specified."));
$form_state->setError($form['add'], t("Invalid user specified."));
}
else {
$user_list[$user->uid] = $user->name;
......@@ -109,7 +129,7 @@ function _acl_edit_form_after_build($form, &$form_state) {
$form['deletions']['#title'] = t("Current users");
$form['deletions']['#options'] = $user_list;
$form['deletions']['#value'] = array(); // don't carry value through.
$form['deletions'] = form_builder(!empty($form['#post']) ? $form['#post']['form_id'] : 'acl_form', $form['deletions'], $form_state);
$form['deletions'] = \Drupal::formBuilder()->doBuildForm(!empty($form['#post']) ? $form['#post']['form_id'] : 'acl_form', $form['deletions'], $form_state);
}
else {
$form['delete_button']['#type'] = 'value';
......@@ -125,23 +145,25 @@ function _acl_edit_form_after_build($form, &$form_state) {
* The module that embedded our form must call this function!
*/
function acl_save_form($form, $priority = NULL) {
$connection = Database::getConnection();
$users = unserialize($form['user_list']);
db_delete('acl_user')
$connection->delete('acl_user')
->condition('acl_id', $form['acl_id'])
->execute();
foreach ($users as $uid => $name) {
db_insert('acl_user')
->fields(array(
$connection->insert('acl_user')
->fields([
'acl_id' => $form['acl_id'],
'uid' => $uid,
))
])
->execute();
}
if (isset($priority)) {
db_update('acl_node')
->fields(array(
$connection->update('acl_node')
->fields([
'priority' => $priority,
))
])
->condition('acl_id', $form['acl_id'])
->execute();
}
......
......@@ -8,10 +8,11 @@
/**
* Explain what your ACL grant records mean.
*/
function hook_acl_explain($acl_id, $name, $number, $users = NULL) {
function hook_acl_explain($acl_id, $name, $figure, $users = NULL) {
if (empty($users)) {
return "ACL (id=$acl_id) would grant access to $name/$number.";
return "ACL (id=$acl_id) would grant access to $name/$figure.";
}
return "ACL (id=$acl_id) grants access to $name/$number to the listed user(s).";
return "ACL (id=$acl_id) grants access to $name/$figure to the listed user(s).";
}
name = ACL
description = Access control list API. Has no features on its own.
core = 7.x
package = Access control
files[] = tests/acl.test
name: ACL
type: module
description: 'Access control list API. Has no features on its own.'
core: 8.x
package: 'Access control'
......@@ -28,15 +28,22 @@ function acl_schema() {
'type' => 'varchar',
'length' => 255,
),
'number' => array(
'description' => "A number for this ACL entry, given by the module that created it; use either 'name' or 'number'.",
'figure' => array(
'description' => "A number for this ACL entry, given by the module that created it; use either 'name' or 'figure'.",
'type' => 'int',
),
),
'primary key' => array('acl_id'),
'indexes' => array(
'module_name_number' => array(array('module', 64), array('name', 64), 'number'),
'module_number' => array(array('module', 64), 'number'),
'module_figure_name' => array(
array('module', 64),
'figure',
array('name', 64),
),
'module_name' => array(
array('module', 64),
'name',
),
),
);
$schema['acl_user'] = array(
......@@ -112,101 +119,6 @@ function acl_schema() {
'nid' => array('nid'),
),
);
return $schema;
}
/**
* Fixes primary keys
*/
function acl_update_2() {
$ret = array();
// drop the previously created indexes (except for acl_user.uid)
db_drop_index($ret, 'acl', 'acl_id');
db_drop_index($ret, 'acl_user', 'acl_id');
db_drop_index($ret, 'acl_node', 'acl_id');
db_drop_index($ret, 'acl_node', 'nid');
// create new indexes (as primary keys this time)
db_add_primary_key($ret, 'acl', array('acl_id'));
db_add_primary_key($ret, 'acl_user', array('acl_id', 'uid'));
db_add_primary_key($ret, 'acl_node', array('acl_id', 'nid'));
return $ret;
}
/**
* Put back acl_node(nid) index for deleting nodes and clean up {acl_node}.
*/
function acl_update_4() {
$ret = array();
db_add_index($ret, 'acl_node', 'nid', array('nid'));
$ret[] = update_sql("DELETE FROM {acl_node} WHERE nid NOT IN (SELECT nid FROM {node})");
return $ret;
}
/**
* Clean up {acl_user}.
*/
function acl_update_5() {
$ret = array();
$ret[] = update_sql("DELETE FROM {acl_user} WHERE uid NOT IN (SELECT uid FROM {users})");
return $ret;
}
/**
* Add 'priority' column.
*/
function acl_update_6() {
$ret = array();
db_add_field($ret, 'acl_node', 'priority', array('type' => 'int', 'size' => 'small', 'not null' => TRUE, 'default' => 0));
return $ret;
}
/**
* Change acl_id to auto-increment.
*/
function acl_update_6000() {
$ret = array();
db_change_field($ret, 'acl', 'acl_id', 'acl_id', array('type' => 'serial', 'not null' => TRUE));
// (Dropping and recreating the primary key on an auto_increment column would cause a MySQL failure.)
db_change_field($ret, 'acl', 'module', 'module', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
db_change_field($ret, 'acl', 'name', 'name', array('type' => 'varchar', 'length' => 255));
db_add_index($ret, 'acl_node', 'nid', array('nid'));
return $ret;
}
/**
* Add index that should have been added when upgrading from D5.
*/
function acl_update_6001() {
$ret = array();
@db_add_index($ret, 'acl_node', 'nid', array('nid'));
return ($ret['success'] ? $ret : array()); // ignore possible error, if the index already exists
}
/**
* Add 'number' column if it's not there yet.
*/
function acl_update_7000() {
if (!db_field_exists('acl', 'number')) {
db_add_field('acl', 'number', array('type' => 'int', 'description' => "A number for this ACL entry, given by the module that created it; use either 'name' or 'number'."));
}
}
/**
* Install better indexes.
*/
function acl_update_7001() {
if (db_index_exists('acl', 'name')) {
db_drop_index('acl', 'name');
}
if (!db_index_exists('acl', 'module_name_number')) {
db_add_index('acl', 'module_name_number', array(array('module', 64), array('name', 64), 'number'));
}
if (db_index_exists('acl', 'number')) {
db_drop_index('acl', 'number');
}
if (!db_index_exists('acl', 'module_number')) {
db_add_index('acl', 'module_number', array(array('module', 64), 'number'));
}
return $schema;
}
This diff is collapsed.
migrate.destination.acl_table:
type: migrate_destination
label: 'Drupal 8 ACL table'
mapping:
table_name:
type: string
label: 'Table name'
fields_list:
type: sequence
label: 'Fields list'
sequence:
type: string
label: 'Field name'
ids:
type: sequence
label: 'Primary key'
sequence:
type: sequence
label: 'ID parameter name'
sequence:
type: string
label: 'ID parameter value'
migrate.source.d6_d7_acl_table:
type: migrate_source_sql
label: 'Drupal 6/7 ACL table'
mapping:
table_name:
type: string
label: 'Table name'
fields_list:
type: sequence
label: 'Fields list'
sequence:
type: string
label: 'Field name'
ids:
type: sequence
label: 'Primary key'
sequence:
type: sequence
label: 'ID parameter name'
sequence:
type: string
label: 'ID parameter value'
id: d6_d7_acl
label: Drupal 6/7 base Access Control Lists table
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: d6_d7_acl_list
process:
acl_id: acl_id
module: module
name: name
figure: number
destination:
plugin: acl_list
id: d6_d7_acl_node
label: Drupal 6/7 Access Control Lists node grants table
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: d6_d7_acl_table
table_name: acl_node
fields_list:
- acl_id
- nid
- grant_view
- grant_update
- grant_delete
- priority
ids:
acl_id:
type: integer
nid:
type: integer
process:
acl_id: acl_id
nid: nid
grant_view: grant_view
grant_update: grant_update
grant_delete: grant_delete
priority: priority
destination:
plugin: acl_table
table_name: acl_node
fields_list:
- acl_id
- nid
- grant_view
- grant_update
- grant_delete
- priority
ids:
acl_id:
type: integer
nid:
type: integer
id: d6_d7_acl_user
label: Drupal 6/7 Access Control Lists users table
migration_tags:
- Drupal 6
- Drupal 7
source:
plugin: d6_d7_acl_table
table_name: acl_user
fields_list:
- acl_id
- uid
ids:
acl_id:
type: integer
uid:
type: integer
process:
acl_id: acl_id
uid: uid
destination:
plugin: acl_table
table_name: acl_user
fields_list:
- acl_id
- uid
ids:
acl_id:
type: integer
uid:
type: integer
<?php
/**
* @file
* Contains \Drupal\acl\Plugin\migrate\destination\AclList.
*/
namespace Drupal\acl\Plugin\migrate\destination;
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Row;
use Drupal\migrate\Entity\MigrationInterface;
/**
* Drupal 8 ACL List Table destination.
*
* @MigrateDestination(
* id = "acl_list"
* )
*/
class AclList extends DestinationBase implements MigrateDestinationInterface {
/**
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = array()) {
$destination = $row->getDestination();
\Drupal::database()->merge('acl')
->key(array('acl_id' => $destination['acl_id']))
->fields(array(
'module' => $destination['module'],
'name' => $destination['name'],
'figure' => $destination['figure'],
))
->execute();
return [$row->getDestinationProperty('acl_id')];
}
/**
* {@inheritdoc}
*/
public function getIds() {
$ids['acl_id']['type'] = 'integer';
return $ids;
}
/**
* {@inheritdoc}
*/
public function fields(MigrationInterface $migration = NULL) {
return [
'acl_id' => $this->t('Primary key: unique ACL ID.'),
'module' => $this->t('The name of the module that created this ACL entry.'),
'name' => $this->t('A name (or other identifying information) for this ACL entry, given by the module that created it.'),
'figure' => $this->t('A number for this ACL entry, given by the module that created it.'),
];
}
}
<?php
/**
* @file
* Contains \Drupal\acl\Plugin\migrate\destination\AclTable.
*/
namespace Drupal\acl\Plugin\migrate\destination;
use Drupal\migrate\Plugin\migrate\destination\DestinationBase;
use Drupal\migrate\Plugin\MigrateDestinationInterface;
use Drupal\migrate\Row;
use Drupal\migrate\Entity\MigrationInterface;
/**
* Drupal 8 ACL Table destination.
*
* @MigrateDestination(
* id = "acl_table"
* )
*/
class AclTable extends DestinationBase implements MigrateDestinationInterface {
/**
* Table name to fetch.
*
* @var array
*/
protected $table_name;
/**
* Field names to fetch.
*
* @var array
*/
protected $fields_list;
/**
* Default Ids for Migrate API.
*
* @var array
*/
protected $ids = [
'acl_id' => [
'type' => 'integer',
],
];
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, MigrationInterface $migration) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $migration);
$this->table_name = $this->configuration['table_name'];
$this->fields_list = $this->configuration['fields_list'];
if (!empty($this->configuration['ids'])) {
$this->ids = $this->configuration['ids'];
}
}
/**
* {@inheritdoc}
*/
public function import(Row $row, array $old_destination_id_values = array()) {
$destination = $row->getDestination();
$keys = array();
foreach(array_keys($this->ids) as $id) {
$keys[$id] = $destination[$id];
unset($destination[$id]);
}
\Drupal::database()->merge($this->table_name)
->keys($keys)
->fields($destination)
->execute();
$return = array_map(function($key) use ($row) {
return $row->getDestinationProperty($key);
}, $keys);
return $return;
}
/**
* {@inheritdoc}
*/
public function getIds() {
return $this->ids;
}
/**
* {@inheritdoc}
*/
public function fields(MigrationInterface $migration = NULL) {
return array_combine($this->fields_list, $this->fields_list);
}
}
<?php
/**
* @file
* Contains \Drupal\acl\Plugin\migrate\source\AclList.
*/
namespace Drupal\acl\Plugin\migrate\source;
use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
/**
* Drupal 6/7 ACL List Table source from database.
*
* @MigrateSource(
* id = "d6_d7_acl_list"
* )
*/
class AclList extends DrupalSqlBase {
/**
* {@inheritdoc}
*/
public function query() {
$query = $this->select('acl', 'a')
->fields('a', [
'acl_id',
'module',
'name',
'number',
]
);
$query->orderBy('acl_id');
return $query;
}
/**
* {@inheritdoc}
*/
public function fields() {
return [
'acl_id' => $this->t('Primary key: unique ACL ID.'),
'module' => $this->t('The name of the module that created this ACL entry.'),
'name' => $this->t('A name (or other identifying information) for this ACL entry, given by the module that created it.'),
'number' => $this->t('A number for this ACL entry, given by the module that created it.'),
];
}
/**