Commit a75535aa authored by Sergii Bondarenko's avatar Sergii Bondarenko

First version of a module

parents
# Environment Field Access
Restrict an access to fields depending on environment.
## Usage
Create an environment via `hook_environment()`, go to editing of any existing
field and configure an access in `Field Access` settings group.
![Field Access settings](help/fieldaccess.png)
## Dependencies
- [Environment](https://www.drupal.org/project/environment)
- [Field Access](https://www.drupal.org/project/fieldaccess)
## Testing
```shell
drush dl simpletest
drush en simpletest -y
drush test-run EnvironmentFieldAccessTestCase
```
<?php
/**
* @file
* Configure access arguments.
*/
/**
* Configure access arguments.
*
* @see callback_fieldaccess_configure()
*/
function environment_fieldaccess_configure(array $settings, array &$form, array &$form_state) {
return _environment_fieldaccess_settings($settings);
}
<?php
/**
* @file
* Check an access.
*/
/**
* Check an access.
*
* @see callback_fieldaccess_grant()
*/
function environment_fieldaccess_grant(array $settings, \stdClass $object, \stdClass $account, array $context) {
$settings = _environment_fieldaccess_settings($settings, TRUE);
$state = array_key_exists(environment_current(), $settings['environment']);
return $settings['not'] ? !$state : $state;
}
name = Environment Field Access
description = Control access of fields depending on configured environment.
package = Field Access
core = 7.x
php = 5.4
testing_api = 2.x
files[] = tests/environment_fieldaccess.test
files[] = tests/environment_fieldaccess.fields.inc
dependencies[] = environment
dependencies[] = fieldaccess
<?php
/**
* @file
* Environment Field Access.
*/
/**
* Implements hook_fieldaccess_info().
*/
function environment_fieldaccess_fieldaccess_info() {
$label = t('Access field depending on environment');
$info = [];
foreach (['edit', 'view'] as $type) {
$data = [
'type' => $type,
'label' => $label,
];
foreach (['configure', 'grant'] as $func) {
$data += [
"{$func}" => "environment_fieldaccess_$func",
"{$func}_file" => "environment_fieldaccess.$func.inc",
];
}
$info["environment_fieldaccess_$type"] = $data;
}
return $info;
}
/**
* Get instance of current site.
*
* @param array $settings
* Configured settings.
* @param bool $get
* Get values.
*
* @return array
* Form definition or, if second argument is TRUE - configured values.
*/
function _environment_fieldaccess_settings(array $settings, $get = FALSE) {
$environments = $elements = $values = [];
if (!$get) {
foreach (environment_load() as $environment => $definition) {
$environments[$environment] = $definition['label'];
}
}
$elements['environment'] = [
'#type' => 'select',
'#title' => t('Allow access for selected environments'),
'#options' => $environments,
'#multiple' => TRUE,
'#default_value' => '',
];
$elements['not'] = [
'#type' => 'checkbox',
'#title' => t('Reverse (NOT)'),
'#default_value' => 0,
];
foreach ($elements as $element => &$definition) {
// Updated default value from settings.
if (isset($settings[$element])) {
$definition['#default_value'] = $settings[$element];
}
// Collect form values.
$values[$element] = isset($definition['#default_value']) ? $definition['#default_value'] : NULL;
}
return $get ? $values : $elements;
}
<?php
/**
* @file
* Environment Field Access (Fields Helper).
*/
/**
* Class EnvironmentFieldAccessFields.
*/
class EnvironmentFieldAccessFields {
private $fields = [];
private $instances = [];
/**
* Set field definitions.
*
* @param array[] $fields
* An associative array where keys - field names and values - definition.
*/
public function __construct(array $fields) {
$this->fields = $fields;
}
/**
* Create fields.
*
* @throws \FieldException
* When cannot create a field.
*/
public function create() {
foreach ($this->fields as $name => $data) {
if (!db_table_exists("field_data_$name")) {
field_create_field($data + [
'default' => '',
'not null' => TRUE,
'field_name' => $name,
]);
}
}
}
/**
* Completely delete fields.
*
* This function deletes tables: "field_data_NAME" and "field_revision_NAME"
* and entries in "field_config" and "field_config_instances".
*/
public function delete() {
foreach (array_keys($this->fields) as $name) {
// Delete tables.
foreach (['data', 'revision'] as $table_type) {
$table = "field_{$table_type}_{$name}";
if (db_table_exists($table)) {
db_drop_table($table);
}
}
// Delete entries.
foreach (['config', 'config_instance'] as $table_type) {
db_delete("field_$table_type")
->condition('field_name', $name)
->execute();
}
}
}
/**
* Attach existing fields into entity.
*
* @param string $entity_type
* Entity machine name.
* @param string $bundle_name
* Entity bundle name.
*
* @throws \FieldException
* When instance cannot be created.
*/
public function attach($entity_type, $bundle_name) {
$attached_fields = field_info_instances($entity_type, $bundle_name);
foreach ($this->fields as $field_name => $data) {
if (empty($attached_fields[$field_name]) && field_info_field($field_name)) {
field_create_instance($data + [
'bundle' => $bundle_name,
'field_name' => $field_name,
'entity_type' => $entity_type,
]);
}
}
}
/**
* Get field instances.
*
* @return array[]
* Field instances.
*/
public function &getInstances() {
if (empty($this->instances)) {
$query = db_select('field_config_instance', 'fci')
->fields('fci', ['field_name', 'data'])
->condition('field_name', array_keys($this->fields))
->execute()
->fetchAllKeyed();
$this->instances = array_map('unserialize', $query);
}
return $this->instances;
}
/**
* Save field instances.
*
* @throws \Exception
* @throws \InvalidMergeQueryException
*/
public function saveInstances() {
foreach ($this->instances as $field_name => $data) {
db_merge('field_config_instance')
->fields(['data' => serialize($data)])
->condition('field_name', $field_name)
->execute();
}
}
}
<?php
/**
* @file
* Environment Field Access (Test).
*/
/**
* Class EnvironmentFieldAccessTestCase.
*/
class EnvironmentFieldAccessTestCase extends \DrupalWebTestCase {
/**
* Name of module for testing. Also used as field name.
*/
const TEST_MODULE = 'environment_fieldaccess_test';
/**
* @var \EnvironmentFieldAccessFields
*/
private $fieldsManager;
/**
* {@inheritdoc}
*/
public function __construct($test_id = NULL) {
// Prevent wrong execution.
if (strpos($GLOBALS['base_url'], 'default') !== FALSE) {
throw new \RuntimeException('Test cannot be run from CLI if $base_url variable not set.');
}
parent::__construct($test_id);
$fieldaccess = [];
foreach (environment_fieldaccess_fieldaccess_info() as $name => $info) {
$fieldaccess[$info['type']] = [
'access_name' => $name,
'individual' => 0,
'settings' => [
'not' => 0,
'environment' => [
'test_show' => 'test_show',
],
],
];
}
$this->fieldsManager = new \EnvironmentFieldAccessFields([
self::TEST_MODULE => [
'type' => 'text',
'label' => self::TEST_MODULE,
'settings' => [
'fieldaccess' => $fieldaccess,
'user_register_form' => TRUE,
],
],
]);
}
/**
* Delete created fields.
*/
public function __destruct() {
$this->fieldsManager->delete();
}
/**
* {@inheritdoc}
*/
public static function getInfo() {
return [
'name' => 'Environment Field Access',
'group' => 'Field API',
'description' => 'Testing field access depending on environment.',
];
}
/**
* {@inheritdoc}
*/
public function setUp() {
// Enable modules.
parent::setUp(self::TEST_MODULE);
// Create fields for testing.
$this->fieldsManager->create();
// Attach field to "user" entity.
$this->fieldsManager->attach('user', 'user');
}
/**
* Access allowed in current environment.
*/
public function testAccessAllowed() {
// Set an environment to "test_show", go to "user/register" and
// try to find the field on a page.
$this->assertEnvironment('test_show');
$this->assertFieldByXPath($this->fieldXpath());
}
/**
* Access disallowed in another environment.
*/
public function testAccessDisallowed() {
// Set an environment to "test_hide", go to "user/register" and
// make sure that field does not exist on a page.
$this->assertEnvironment('test_hide');
$this->assertNoFieldByXPath($this->fieldXpath());
}
/**
* Access disallowed in current environment ("not" option selected).
*/
public function testNotAccessAllowed() {
// Set an environment to "test_show", go to "user/register" and
// make sure that field does not exist on a page, because "not"
// option is selected.
$instances =& $this->fieldsManager->getInstances();
foreach ($instances[self::TEST_MODULE]['settings']['fieldaccess'] as $type => &$info) {
$info['settings']['not'] = 1;
}
$this->fieldsManager->saveInstances();
$this->assertEnvironment('test_show');
$this->assertNoFieldByXPath($this->fieldXpath());
}
/**
* Switch the environment.
*
* @param string $environment
* Environment name.
*/
private function assertEnvironment($environment) {
$this->assertTrue(environment_switch($environment));
$this->assertTrue(environment_current() === $environment);
$this->drupalGet('user/register');
$this->assertResponse(200);
}
/**
* Build XPath of field.
*
* @return string
* Field XPath.
*/
private function fieldXpath() {
return $this->buildXPathQuery('//label[text()[starts-with(., :text)]]', [
':text' => self::TEST_MODULE,
]);
}
}
name = Environment Field Access (Test)
package = Field
hidden = TRUE
core = 7.x
php = 5.4
dependencies[] = environment_fieldaccess
<?php
/**
* @file
* Environment Field Access (Test).
*/
/**
* Implements hook_environment().
*/
function environment_fieldaccess_test_environment() {
$environments = [];
$environments['test_show'] = [
'label' => t('Environment for testing'),
'description' => t('Environment, where fields are available'),
];
$environments['test_hide'] = [
'label' => t('Environment for testing'),
'description' => t('Environment, where fields are not available'),
];
return $environments;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment