added example for developpers module

This commit is contained in:
Bachir Soussi Chiadmi
2018-01-06 11:28:03 +01:00
parent 5017966908
commit 5ec2f4311c
396 changed files with 26299 additions and 0 deletions
@@ -0,0 +1,15 @@
name: DBTNG Example
type: module
description: 'Demonstrates how to use the database API: DBTNG.'
package: Example modules
# core: 8.x
dependencies:
- drupal:node
- drupal:user
- examples:examples
# Information added by Drupal.org packaging script on 2017-12-17
version: '8.x-1.x-dev'
core: '8.x'
project: 'examples'
datestamp: 1513537386
@@ -0,0 +1,95 @@
<?php
/**
* @file
* Install, update and uninstall functions for the dbtng_example module.
*/
/**
* Implements hook_install().
*
* Creates some default entries on this module custom table.
*
* @see hook_install()
*
* @ingroup dbtng_example
*/
function dbtng_example_install() {
// Add a default entry.
$fields = [
'name' => 'John',
'surname' => 'Doe',
'age' => 0,
];
db_insert('dbtng_example')
->fields($fields)
->execute();
// Add another entry.
$fields = [
'name' => 'John',
'surname' => 'Roe',
'age' => 100,
'uid' => 1,
];
db_insert('dbtng_example')
->fields($fields)
->execute();
}
/**
* Implements hook_schema().
*
* Defines the database tables used by this module.
*
* @see hook_schema()
*
* @ingroup dbtng_example
*/
function dbtng_example_schema() {
$schema['dbtng_example'] = [
'description' => 'Stores example person entries for demonstration purposes.',
'fields' => [
'pid' => [
'type' => 'serial',
'not null' => TRUE,
'description' => 'Primary Key: Unique person ID.',
],
'uid' => [
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'description' => "Creator user's {users}.uid",
],
'name' => [
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Name of the person.',
],
'surname' => [
'type' => 'varchar',
'length' => 255,
'not null' => TRUE,
'default' => '',
'description' => 'Surname of the person.',
],
'age' => [
'type' => 'int',
'not null' => TRUE,
'default' => 0,
'size' => 'tiny',
'description' => 'The age of the person in years.',
],
],
'primary key' => ['pid'],
'indexes' => [
'name' => ['name'],
'surname' => ['surname'],
'age' => ['age'],
],
];
return $schema;
}
@@ -0,0 +1,25 @@
dbtng_example.description:
title: DBTNG Example
route_name: dbtng_example
expanded: TRUE
dbtng_example.list:
title: List
route_name: dbtng_list
weight: 0
parent: dbtng_example.description
dbtng_example.add:
title: Add entry
route_name: dbtng_add
weight: 1
parent: dbtng_example.description
dbtng_example.update:
title: Update entry
route_name: dbtng_update
weight: 2
parent: dbtng_example.description
dbtng_example.advanced:
title: Advanced list
route_name: dbtng_advanced
weight: 3
parent: dbtng_example.description
@@ -0,0 +1,63 @@
<?php
/**
* @file
* This is an example outlining how a module can use the DBTNG database API.
*
* @todo Demonstrate transaction usage.
*
* General documentation is available at
* @link database Database abstraction layer documentation @endlink and
* at @link http://drupal.org/node/310069 @endlink.
*/
/**
* @defgroup dbtng_example Example: Database (DBTNG)
* @ingroup examples
* @{
* Database examples, including DBTNG.
*
* 'DBTNG' means 'Database: The Next Generation.' Yes, Drupallers are nerds.
*
* General documentation is available at
* @link database.inc database abstraction layer documentation @endlink and
* at @link http://drupal.org/node/310069 Database API @endlink.
*
* The several examples in DbtngExampleController (see
* /src/Drupal/dbtng_example/Controller/DbtngExampleController.php) demonstrate
* basic database usage.
*
* db_insert() example:
* @code
* // INSERT INTO {dbtng_example} (name, surname) VALUES('John, 'Doe')
* db_insert('dbtng_example')
* ->fields(array('name' => 'John', 'surname' => 'Doe'))
* ->execute();
* @endcode
*
* db_update() example:
* @code
* // UPDATE {dbtng_example} SET name = 'Jane' WHERE name = 'John'
* db_update('dbtng_example')
* ->fields(array('name' => 'Jane'))
* ->condition('name', 'John')
* ->execute();
* @endcode
*
* db_delete() example:
* @code
* // DELETE FROM {dbtng_example} WHERE name = 'Jane'
* db_delete('dbtng_example')
* ->condition('name', 'Jane')
* ->execute();
* @endcode
*
* See @link database Database Abstraction Layer @endlink
* @see db_insert()
* @see db_update()
* @see db_delete()
*/
/**
* @} End of "defgroup dbtng_example".
*/
@@ -0,0 +1,39 @@
dbtng_example:
path: 'examples/dbtng-example'
defaults:
_title: 'DBTNG Example'
_controller: '\Drupal\dbtng_example\Controller\DbtngExampleController::entryList'
requirements:
_permission: 'access content'
dbtng_list:
path: 'examples/dbtng-example/list'
defaults:
_title: 'List'
_controller: '\Drupal\dbtng_example\Controller\DbtngExampleController::entryList'
requirements:
_permission: 'access content'
dbtng_add:
path: 'examples/dbtng-example/add'
defaults:
_title: 'Add entry'
_form: '\Drupal\dbtng_example\Form\DbtngExampleAddForm'
requirements:
_permission: 'access content'
dbtng_update:
path: 'examples/dbtng-example/update'
defaults:
_title: 'Update entry'
_form: '\Drupal\dbtng_example\Form\DbtngExampleUpdateForm'
requirements:
_permission: 'access content'
dbtng_advanced:
path: 'examples/dbtng-example/advanced'
defaults:
_title: 'Advanced list'
_controller: '\Drupal\dbtng_example\Controller\DbtngExampleController::entryAdvancedList'
requirements:
_permission: 'access content'
@@ -0,0 +1,78 @@
<?php
namespace Drupal\dbtng_example\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\dbtng_example\DbtngExampleStorage;
/**
* Controller for DBTNG Example.
*/
class DbtngExampleController extends ControllerBase {
/**
* Render a list of entries in the database.
*/
public function entryList() {
$content = [];
$content['message'] = [
'#markup' => $this->t('Generate a list of all entries in the database. There is no filter in the query.'),
];
$rows = [];
$headers = [t('Id'), t('uid'), t('Name'), t('Surname'), t('Age')];
foreach ($entries = DbtngExampleStorage::load() as $entry) {
// Sanitize each entry.
$rows[] = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', (array) $entry);
}
$content['table'] = [
'#type' => 'table',
'#header' => $headers,
'#rows' => $rows,
'#empty' => t('No entries available.'),
];
// Don't cache this page.
$content['#cache']['max-age'] = 0;
return $content;
}
/**
* Render a filtered list of entries in the database.
*/
public function entryAdvancedList() {
$content = [];
$content['message'] = [
'#markup' => $this->t('A more complex list of entries in the database.') . ' ' .
$this->t('Only the entries with name = "John" and age older than 18 years are shown, the username of the person who created the entry is also shown.'),
];
$headers = [
t('Id'),
t('Created by'),
t('Name'),
t('Surname'),
t('Age'),
];
$rows = [];
foreach ($entries = DbtngExampleStorage::advancedLoad() as $entry) {
// Sanitize each entry.
$rows[] = array_map('Drupal\Component\Utility\SafeMarkup::checkPlain', $entry);
}
$content['table'] = [
'#type' => 'table',
'#header' => $headers,
'#rows' => $rows,
'#attributes' => ['id' => 'dbtng-example-advanced-list'],
'#empty' => t('No entries available.'),
];
// Don't cache this page.
$content['#cache']['max-age'] = 0;
return $content;
}
}
@@ -0,0 +1,222 @@
<?php
namespace Drupal\dbtng_example;
/**
* Class DbtngExampleStorage.
*/
class DbtngExampleStorage {
/**
* Save an entry in the database.
*
* The underlying DBTNG function is db_insert().
*
* Exception handling is shown in this example. It could be simplified
* without the try/catch blocks, but since an insert will throw an exception
* and terminate your application if the exception is not handled, it is best
* to employ try/catch.
*
* @param array $entry
* An array containing all the fields of the database record.
*
* @return int
* The number of updated rows.
*
* @throws \Exception
* When the database insert fails.
*
* @see db_insert()
*/
public static function insert(array $entry) {
$return_value = NULL;
try {
$return_value = db_insert('dbtng_example')
->fields($entry)
->execute();
}
catch (\Exception $e) {
drupal_set_message(t('db_insert failed. Message = %message, query= %query', [
'%message' => $e->getMessage(),
'%query' => $e->query_string,
]
), 'error');
}
return $return_value;
}
/**
* Update an entry in the database.
*
* @param array $entry
* An array containing all the fields of the item to be updated.
*
* @return int
* The number of updated rows.
*
* @see db_update()
*/
public static function update(array $entry) {
try {
// db_update()...->execute() returns the number of rows updated.
$count = db_update('dbtng_example')
->fields($entry)
->condition('pid', $entry['pid'])
->execute();
}
catch (\Exception $e) {
drupal_set_message(t('db_update failed. Message = %message, query= %query', [
'%message' => $e->getMessage(),
'%query' => $e->query_string,
]
), 'error');
}
return $count;
}
/**
* Delete an entry from the database.
*
* @param array $entry
* An array containing at least the person identifier 'pid' element of the
* entry to delete.
*
* @see db_delete()
*/
public static function delete(array $entry) {
db_delete('dbtng_example')
->condition('pid', $entry['pid'])
->execute();
}
/**
* Read from the database using a filter array.
*
* The standard function to perform reads was db_query(), and for static
* queries, it still is.
*
* db_query() used an SQL query with placeholders and arguments as parameters.
*
* Drupal DBTNG provides an abstracted interface that will work with a wide
* variety of database engines.
*
* db_query() is deprecated except when doing a static query. The following is
* perfectly acceptable in Drupal 8. See
* @link http://drupal.org/node/310072 the handbook page on static queries @endlink
*
* @code
* // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
* db_query(
* "SELECT * FROM {dbtng_example} WHERE uid = :uid and name = :name",
* array(':uid' => 0, ':name' => 'John')
* )->execute();
* @endcode
*
* But for more dynamic queries, Drupal provides the db_select()
* API method, so there are several ways to perform the same SQL query. See
* the
* @link http://drupal.org/node/310075 handbook page on dynamic queries. @endlink
* @code
* // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
* db_select('dbtng_example')
* ->fields('dbtng_example')
* ->condition('uid', 0)
* ->condition('name', 'John')
* ->execute();
* @endcode
*
* Here is db_select with named placeholders:
* @code
* // SELECT * FROM {dbtng_example} WHERE uid = 0 AND name = 'John'
* $arguments = array(':name' => 'John', ':uid' => 0);
* db_select('dbtng_example')
* ->fields('dbtng_example')
* ->where('uid = :uid AND name = :name', $arguments)
* ->execute();
* @endcode
*
* Conditions are stacked and evaluated as AND and OR depending on the type of
* query. For more information, read the conditional queries handbook page at:
* http://drupal.org/node/310086
*
* The condition argument is an 'equal' evaluation by default, but this can be
* altered:
* @code
* // SELECT * FROM {dbtng_example} WHERE age > 18
* db_select('dbtng_example')
* ->fields('dbtng_example')
* ->condition('age', 18, '>')
* ->execute();
* @endcode
*
* @param array $entry
* An array containing all the fields used to search the entries in the
* table.
*
* @return object
* An object containing the loaded entries if found.
*
* @see db_select()
* @see db_query()
* @see http://drupal.org/node/310072
* @see http://drupal.org/node/310075
*/
public static function load(array $entry = []) {
// Read all fields from the dbtng_example table.
$select = db_select('dbtng_example', 'example');
$select->fields('example');
// Add each field and value as a condition to this query.
foreach ($entry as $field => $value) {
$select->condition($field, $value);
}
// Return the result in object format.
return $select->execute()->fetchAll();
}
/**
* Load dbtng_example records joined with user records.
*
* DBTNG also helps processing queries that return several rows, providing the
* found objects in the same query execution call.
*
* This function queries the database using a JOIN between users table and the
* example entries, to provide the username that created the entry, and
* creates a table with the results, processing each row.
*
* SELECT
* e.pid as pid, e.name as name, e.surname as surname, e.age as age
* u.name as username
* FROM
* {dbtng_example} e
* JOIN
* users u ON e.uid = u.uid
* WHERE
* e.name = 'John' AND e.age > 18
*
* @see db_select()
* @see http://drupal.org/node/310075
*/
public static function advancedLoad() {
$select = db_select('dbtng_example', 'e');
// Join the users table, so we can get the entry creator's username.
$select->join('users_field_data', 'u', 'e.uid = u.uid');
// Select these specific fields for the output.
$select->addField('e', 'pid');
$select->addField('u', 'name', 'username');
$select->addField('e', 'name');
$select->addField('e', 'surname');
$select->addField('e', 'age');
// Filter only persons named "John".
$select->condition('e.name', 'John');
// Filter only persons older than 18 years.
$select->condition('e.age', 18, '>');
// Make sure we only get items 0-49, for scalability reasons.
$select->range(0, 50);
$entries = $select->execute()->fetchAll(\PDO::FETCH_ASSOC);
return $entries;
}
}
@@ -0,0 +1,130 @@
<?php
namespace Drupal\dbtng_example\Form;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\FormInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\dbtng_example\DbtngExampleStorage;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Form to add a database entry, with all the interesting fields.
*/
class DbtngExampleAddForm implements FormInterface, ContainerInjectionInterface {
use StringTranslationTrait;
/**
* The current user.
*
* We'll need this service in order to check if the user is logged in.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* {@inheritdoc}
*
* We'll use the ContainerInjectionInterface pattern here to inject the
* current user and also get the string_translation service.
*/
public static function create(ContainerInterface $container) {
$form = new static(
$container->get('current_user')
);
// The StringTranslationTrait trait manages the string translation service
// for us. We can inject the service here.
$form->setStringTranslation($container->get('string_translation'));
return $form;
}
/**
* Construct the new form object.
*/
public function __construct(AccountProxyInterface $current_user) {
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'dbtng_add_form';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state) {
$form = [];
$form['message'] = [
'#markup' => $this->t('Add an entry to the dbtng_example table.'),
];
$form['add'] = [
'#type' => 'fieldset',
'#title' => $this->t('Add a person entry'),
];
$form['add']['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#size' => 15,
];
$form['add']['surname'] = [
'#type' => 'textfield',
'#title' => $this->t('Surname'),
'#size' => 15,
];
$form['add']['age'] = [
'#type' => 'textfield',
'#title' => $this->t('Age'),
'#size' => 5,
'#description' => $this->t("Values greater than 127 will cause an exception. Try it - it's a great example why exception handling is needed with DTBNG."),
];
$form['add']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Add'),
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Verify that the user is logged-in.
if ($this->currentUser->isAnonymous()) {
$form_state->setError($form['add'], $this->t('You must be logged in to add values to the database.'));
}
// Confirm that age is numeric.
if (!intval($form_state->getValue('age'))) {
$form_state->setErrorByName('age', $this->t('Age needs to be a number'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Gather the current user so the new record has ownership.
$account = $this->currentUser;
// Save the submitted entry.
$entry = [
'name' => $form_state->getValue('name'),
'surname' => $form_state->getValue('surname'),
'age' => $form_state->getValue('age'),
'uid' => $account->id(),
];
$return = DbtngExampleStorage::insert($entry);
if ($return) {
drupal_set_message($this->t('Created entry @entry', ['@entry' => print_r($entry, TRUE)]));
}
}
}
@@ -0,0 +1,153 @@
<?php
namespace Drupal\dbtng_example\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\dbtng_example\DbtngExampleStorage;
/**
* Sample UI to update a record.
*/
class DbtngExampleUpdateForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'dbtng_update_form';
}
/**
* Sample UI to update a record.
*/
public function buildForm(array $form, FormStateInterface $form_state) {
// Wrap the form in a div.
$form = [
'#prefix' => '<div id="updateform">',
'#suffix' => '</div>',
];
// Add some explanatory text to the form.
$form['message'] = [
'#markup' => $this->t('Demonstrates a database update operation.'),
];
// Query for items to display.
$entries = DbtngExampleStorage::load();
// Tell the user if there is nothing to display.
if (empty($entries)) {
$form['no_values'] = [
'#value' => t('No entries exist in the table dbtng_example table.'),
];
return $form;
}
$keyed_entries = [];
foreach ($entries as $entry) {
$options[$entry->pid] = t('@pid: @name @surname (@age)', [
'@pid' => $entry->pid,
'@name' => $entry->name,
'@surname' => $entry->surname,
'@age' => $entry->age,
]);
$keyed_entries[$entry->pid] = $entry;
}
// Grab the pid.
$pid = $form_state->getValue('pid');
// Use the pid to set the default entry for updating.
$default_entry = !empty($pid) ? $keyed_entries[$pid] : $entries[0];
// Save the entries into the $form_state. We do this so the AJAX callback
// doesn't need to repeat the query.
$form_state->setValue('entries', $keyed_entries);
$form['pid'] = [
'#type' => 'select',
'#options' => $options,
'#title' => t('Choose entry to update'),
'#default_value' => $default_entry->pid,
'#ajax' => [
'wrapper' => 'updateform',
'callback' => [$this, 'updateCallback'],
],
];
$form['name'] = [
'#type' => 'textfield',
'#title' => t('Updated first name'),
'#size' => 15,
'#default_value' => $default_entry->name,
];
$form['surname'] = [
'#type' => 'textfield',
'#title' => t('Updated last name'),
'#size' => 15,
'#default_value' => $default_entry->surname,
];
$form['age'] = [
'#type' => 'textfield',
'#title' => t('Updated age'),
'#size' => 4,
'#default_value' => $default_entry->age,
'#description' => t('Values greater than 127 will cause an exception'),
];
$form['submit'] = [
'#type' => 'submit',
'#value' => t('Update'),
];
return $form;
}
/**
* AJAX callback handler for the pid select.
*
* When the pid changes, populates the defaults from the database in the form.
*/
public function updateCallback(array $form, FormStateInterface $form_state) {
// Gather the DB results from $form_state.
$entries = $form_state->getValue('entries');
// Use the specific entry for this $form_state.
$entry = $entries[$form_state->getValue('pid')];
// Setting the #value of items is the only way I was able to figure out
// to get replaced defaults on these items. #default_value will not do it
// and shouldn't.
foreach (['name', 'surname', 'age'] as $item) {
$form[$item]['#value'] = $entry->$item;
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateForm(array &$form, FormStateInterface $form_state) {
// Confirm that age is numeric.
if (!intval($form_state->getValue('age'))) {
$form_state->setErrorByName('age', t('Age needs to be a number'));
}
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
// Gather the current user so the new record has ownership.
$account = $this->currentUser();
// Save the submitted entry.
$entry = [
'pid' => $form_state->getValue('pid'),
'name' => $form_state->getValue('name'),
'surname' => $form_state->getValue('surname'),
'age' => $form_state->getValue('age'),
'uid' => $account->id(),
];
$count = DbtngExampleStorage::update($entry);
drupal_set_message(t('Updated entry @entry (@count row updated)', [
'@count' => $count,
'@entry' => print_r($entry, TRUE),
]));
}
}
@@ -0,0 +1,222 @@
<?php
namespace Drupal\Tests\dbtng_example\Functional;
use Drupal\dbtng_example\DbtngExampleStorage;
use Drupal\Tests\examples\Functional\ExamplesBrowserTestBase;
/**
* Tests for the dbtng_example module.
*
* @group dbtng_example
* @group examples
*
* @ingroup dbtng_example
*/
class DbtngExampleTest extends ExamplesBrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['dbtng_example'];
/**
* The installation profile to use with this test.
*
* We need the 'minimal' profile in order to make sure the Tool block is
* available.
*
* @var string
*/
protected $profile = 'minimal';
/**
* Regression test for dbtng_example.
*
* We'll verify the following:
* - Assert that two entries were inserted at install.
* - Test the example description page.
* - Verify that the example pages have links in the Tools menu.
*/
public function testDbtngExample() {
$assert = $this->assertSession();
// Assert that two entries were inserted at install.
$result = DbtngExampleStorage::load();
$this->assertCount(2, $result, 'Did not find two entries in the table after installing the module.');
// Test the example description page.
$this->drupalGet('/examples/dbtng-example');
$assert->statusCodeEquals(200);
// Verify and validate that default menu links were loaded for this module.
$links = $this->providerMenuLinks();
foreach ($links as $page => $hrefs) {
foreach ($hrefs as $href) {
$this->drupalGet($page);
$assert->linkByHrefExists($href);
}
}
}
/**
* Data provider for testing menu links.
*
* @return array
* Array of page -> link relationships to check for:
* - The key is the path to the page where our link should appear.
* - The value is an array of links that should appear on that page.
*/
protected function providerMenuLinks() {
return [
'' => [
'/examples/dbtng-example',
],
'/examples/dbtng-example' => [
'/examples/dbtng-example/add',
'/examples/dbtng-example/update',
'/examples/dbtng-example/advanced',
],
];
}
/**
* Test the UI.
*/
public function testUi() {
$assert = $this->assertSession();
$this->drupalLogin($this->createUser());
// Test the basic list.
$this->drupalGet('/examples/dbtng-example');
$assert->statusCodeEquals(200);
$assert->pageTextMatches('%John[td/<>\w\s]+Doe%');
// Test the add tab.
// Add the new entry.
$this->drupalPostForm(
'/examples/dbtng-example/add',
[
'name' => 'Some',
'surname' => 'Anonymous',
'age' => 33,
],
'Add'
);
// Now find the new entry.
$this->drupalGet('/examples/dbtng-example');
$assert->pageTextMatches('%Some[td/<>\w\s]+Anonymous%');
// Try the update tab.
// Find out the pid of our "anonymous" guy.
$result = DbtngExampleStorage::load(['surname' => 'Anonymous']);
$this->drupalGet('/examples/dbtng-example');
$this->assertCount(1, $result, 'Did not find one entry in the table with surname = "Anonymous".');
$entry = $result[0];
unset($entry->uid);
$entry = ['name' => 'NewFirstName', 'age' => 22];
$this->drupalPostForm('/examples/dbtng-example/update', $entry, 'Update');
// Now find the new entry.
$this->drupalGet('/examples/dbtng-example');
$assert->pageTextMatches('%NewFirstName[td/<>\w\s]+Anonymous%');
// Try the advanced tab.
$this->drupalGet('/examples/dbtng-example/advanced');
$rows = $this->xpath("//*[@id='dbtng-example-advanced-list'][1]/tbody/tr");
$this->assertCount(1, $rows);
$field = $this->xpath("//*[@id='dbtng-example-advanced-list'][1]/tbody/tr/td[4]");
$this->assertEquals('Roe', $field[0]->getText());
// Try to add an entry while logged out.
$this->drupalLogout();
$this->drupalPostForm(
'/examples/dbtng-example/add',
[
'name' => 'Anonymous',
'surname' => 'UserCannotPost',
'age' => 'not a number',
],
'Add'
);
$assert->pageTextContains('You must be logged in to add values to the database.');
$assert->pageTextContains('Age needs to be a number');
}
/**
* Tests several combinations, adding entries, updating and deleting.
*/
public function testDbtngExampleStorage() {
// Create a new entry.
$entry = [
'name' => 'James',
'surname' => 'Doe',
'age' => 23,
];
DbtngExampleStorage::insert($entry);
// Save another entry.
$entry = [
'name' => 'Jane',
'surname' => 'NotDoe',
'age' => 19,
];
DbtngExampleStorage::insert($entry);
// Verify that 4 records are found in the database.
$result = DbtngExampleStorage::load();
$this->assertCount(4, $result);
// Verify 2 of these records have 'Doe' as surname.
$result = DbtngExampleStorage::load(['surname' => 'Doe']);
$this->assertCount(2, $result, 'Did not find two entries in the table with surname = "Doe".');
// Now find our not-Doe entry.
$result = DbtngExampleStorage::load(['surname' => 'NotDoe']);
// Found one entry in the table with surname "NotDoe'.
$this->assertCount(1, $result, 'Did not find one entry in the table with surname "NotDoe');
// Our NotDoe will be changed to "NowDoe".
$entry = $result[0];
$entry->surname = "NowDoe";
// update() returns the number of entries updated.
$this->assertNotEquals(DbtngExampleStorage::update((array) $entry), 0);
$result = DbtngExampleStorage::load(['surname' => 'NowDoe']);
$this->assertCount(1, $result, "Did not find renamed 'NowDoe' surname.");
// Read only John Doe entry.
$result = DbtngExampleStorage::load(['name' => 'John', 'surname' => 'Doe']);
$this->assertCount(1, $result, 'Did not find one entry for John Doe.');
// Get the entry.
$entry = (array) end($result);
// Change age to 45.
$entry['age'] = 45;
// Update entry in database.
DbtngExampleStorage::update((array) $entry);
// Find entries with age = 45.
// Read only John Doe entry.
$result = DbtngExampleStorage::load(['surname' => 'NowDoe']);
// Found one entry with surname = Nowdoe.
$this->assertCount(1, $result, 'Did not find one entry with surname = Nowdoe.');
// Verify it is Jane NowDoe.
$entry = (array) end($result);
// The name Jane is found in the entry.
$this->assertEquals('Jane', $entry['name'], 'The name Jane is not found in the entry.');
// The surname NowDoe is found in the entry.
$this->assertEquals('NowDoe', $entry['surname'], 'The surname NowDoe is not found in the entry.');
// Delete the entry.
DbtngExampleStorage::delete($entry);
// Verify that now there are only 3 records.
$result = DbtngExampleStorage::load();
// Found only three records, a record was deleted.
$this->assertCount(3, $result, 'Did not find only three records, a record might not have been deleted.');
}
}