D8: Db, FAPI
Database...
Connection
Schema
Database
Query*
Driver*
← front controller
mysql
pgsql
sqlite
Queries...
Static
Dynamic
// #ref system_update_8001 L:1189
$max = \Drupal::database()->query('SELECT COUNT(mlid) FROM {menu_tree}');
// \Drupal\contact\Plugin\migrate\source\ContactSettings
// ::initializeIterator
$default_category_query = $connection->select('contact', 'c')
->fields('c', ['cid'])
->condition('c.selected', 1);
auto-executed
to run query use execute()
Queries...
some other examples:
// Simple SELECT
$connection->select('url_alias', 'u')
->fields('u', array('pid'))
->condition('source', $source . '%', 'LIKE')
->execute()
->fetchCol();
// Adding *NULL conditions
$query->isNull('ws.entity_type');
$query->isNotNull('ws.entity_id');
// SELECT with OR conditions in second group.
$query = $connection->select('test');
$query->addField('test', 'job');
$query->condition('name', 'Paul');
$query->condition(
(new Condition('OR'))
->condition('age', 26)
->condition('age', 27)
);
$query->execute()->fetchField();
// INSERT
$connection->insert('key_value')
->fields([
'collection' => 'system.schema',
'name' => 'rest',
'value' => 'i:8000;',
])
->execute();
// DELETE
\Drupal::database()->delete('webform_submission_log')
->condition('webform_id', $webform_ids, 'NOT IN')
->execute();
// UPDATE
$connection->update('taxonomy_term_field_data')
->fields(['weight' => 0])
->condition('vid', $vid)
->execute();
// MERGE
$connection->merge('config')
->condition('name', 'system.cron')
->condition('collection', '')
->fields([
'name' => 'system.cron',
'collection' => '',
])
->execute();
// UPSERT
$upsert = $connection->upsert('test_people')
->key('job')
->fields(['job']);
->values([ // Add a new row.
'job' => 'Presenter',
])
->values([ // Update an existing row.
'job' => 'Speaker',
]);
->execute();
Schema...
to Define
to Update
\Drupal::database()->schema()->addField();
use hook_schema
Op
Subject
- Table
- Column
- Index
- Primary key
- Unique key
create, rename, drop
add, change, drop, find
add, drop
add, drop
add, drop
Form API
= class FormBase
+ states API
+ Ajax API
+ abstract FormElement (s)
Actually+...
/(class|interface|trait) (\w+Form\w*) /g
...form workflow
build* — process *— validate** — submit**
* - can be a callable
* - step is exposed in FormInterface
new Render elements
Range
Search
Tel
View...
HtmlTag
InlineTemplate
MoreLink...
use Drupal\Core\Render\Element\RenderElement;
// use either above or below one.
use Drupal\Core\Render\Element\FormElement;
ToggleElement
form redirects
class LanguageMappingChangeForm extends FormBase {
...
public function submitForm(array &$form, FormStateInterface $form_state) {
$form_state->setRedirect('global_gateway_ui.region', [
'region_code' => $mapping->id(),
]);
}
...
}
// OR, if you want to force redirect.
$redirect = Url::fromRoute('translation_outdated.bulk_confirm');
// Skip kernel events VIEW, RESPONSE, TERMINATE.
header('Location: /' . $redirect->getInternalPath()); exit;
#states
API
Adds JavaScript to change the state of an element based on another element.
$form['live_preview']['options']['ui_show_sql_query_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show the SQL query'),
];
$form['live_preview']['options']['ui_show_sql_query_where'] = [
'#type' => 'radios',
'#states' => [
'visible' => [
':input[name="ui_show_sql_query_enabled"]' => [
'checked' => TRUE
],
],
],
'#title' => t('Show SQL query'),
'#options' => [
'above' => $this->t('Above the preview'),
'below' => $this->t('Below the preview'),
],
];
#states
[
STATE1 => CONDITIONS_ARRAY1,
STATE2 => CONDITIONS_ARRAY2,
...
]
most popular state is a visible
90% usage
[
STATE1 => [ // could be `visible`, `invisible`, etc.
JQUERY_SELECTOR => REMOTE_CONDITIONS,
JQUERY_SELECTOR => REMOTE_CONDITIONS,
...
],
]
$form['live_preview']['options']['ui_show_sql_query_enabled'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show the SQL query'),
];
$form['live_preview']['options']['ui_show_sql_query_where'] = [
'#states' => [
'visible' => [
':input[name="ui_show_sql_query_enabled"]' => [
'checked' => TRUE
],
],
],
...
#states
[
'visible' => [
JQUERY_SELECTOR => REMOTE_CONDITIONS,
JQUERY_SELECTOR => REMOTE_CONDITIONS,
...
],
]
conjunction
⇣
[
'enabled' => [
[
JQUERY_SELECTOR1 => REMOTE_CONDITIONS1,
JQUERY_SELECTOR2 => REMOTE_CONDITIONS2,
],
'or', // could be `xor`
[JQUERY_SELECTOR => REMOTE_CONDITIONS],
...
],
]
AND
OR
AND
$row['condition']['value'] = [
'#type' => 'textfield',
'#title' => t('Value'),
'#title_display' => 'invisible',
'#size' => 25,
'#default_value' => $condition['value'],
'#placeholder' => t('Enter value...'),
'#states' => [
'visible' => [
[$trigger_selector => ['value' => 'value']],
'or',
[$trigger_selector => ['value' => '!value']],
'or',
[$trigger_selector => ['value' => 'pattern']],
'or',
[$trigger_selector => ['value' => '!pattern']],
'or',
[$trigger_selector => ['value' => 'greater']],
'or',
[$trigger_selector => ['value' => 'less']],
],
],
'#wrapper_attributes' => ['class' => ['webform-states-table--value']],
'#parents' => [$element_name, 'states', $row_index , 'value'],
];
tricks
[
'#type' => 'markup',
'#states' => [...],
]
#states
[
'#type' => 'container',
'#states' => [...],
'markup_el' => [
'#type' => 'markup',
]
]
AJAX
API
When?
dynamically updating parts of a page's HTML based on data from the server
triggered by
Forms
#ajax
Links
`use-ajax` class
Form submit button
`use-ajax-submit` class
in Forms
Add property '#ajax'
Write an Ajax callback to process the input
1
AJAX
2
3
Respond either with render array, html, or Responce
-> part of form
1
AJAX in forms
2
3
public function buildForm(array $form, FormStateInterface $form_state) {
$wrapper = [
'#type' => 'container',
'#attributes' => ['id' => 'languages-wrap']
];
$wrapper['add_more'] = [
'#type' => 'submit',
'#name' => 'add_more',
'#value' => t('Add Language'),
'#submit' => [[self::class, 'rebuildForm']],
'#ajax' => [
'callback' => [self::class, 'updateLanguagesCallback'],
'wrapper' => 'languages-list',
'effect' => 'fade',
],
];
// Rebuilding of the form elements should be in this method.
...
public static function updateLanguagesCallback(array &$form, FormStateInterface $form_state) {
...
}
public static function rebuildForm(array &$form, FormStateInterface $form_state) {
$form_state->setRebuild();
}
public static function updateLanguagesCallback(array &$form, FormStateInterface $form_state) {
return $form['languages_wrap']['languages'];
}
->Responce
1
AJAX in forms
2
3
public function buildForm(array $form, FormStateInterface $form_state) {
$this->regionCode = $form_state->get('current_region');
$region = [
'#type' => 'select',
'#title' => $this->t('Region'),
'#options' => $regions,
'#ajax' => [
'callback' => '::updateBlock',
'wrapper' => 'new-region-list',
'effect' => 'fade',
'event' => 'change',
],
'#attributes' => ['class' => ['global-gateway-region']],
];
return $form;
}
public function updateBlock(array $form, FormStateInterface $form_state) {
...
}
public function updateBlock(array $form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
$ajax_response->addCommand(new ReplaceCommand($selector , $form['items']));
$ajax_response->addCommand(new InvokeCommand(NULL, 'globalGatewayEmmitRegionChange', []));
return $ajax_response;
}
in Links
Add class 'use-ajax' to the link
Write an Ajax callback to process the input
1
AJAX
2
3
Respond either with render array, html, or Responce
-> RA
1
AJAX via links
2
3
private static function buildExtraOptionsLink($sample_id) {
$loadLink = [
'link' => [
'#title' => 'Configure',
'#type' => 'link',
'#url' => Url::fromRoute('product_manager.extra_options', ['sample_id' => $sample_id]),
'#localized_options' => array('html' => TRUE),
],
];
$loadLink['link']['#attributes']['class'][] = 'use-ajax';
return [
'#type' => 'inline_template',
'#template' => '{{ link | raw }}',
'#context' => ['link' => $loadLink],
];
}
// routing.yml
product_manager.extra_options:
path: '/admin/products/samples/{sample_id}/extra_options'
defaults:
_controller: 'Drupal\product_manager\Controller\ExtraOptionsController::openModalForm'
// ExtraOptionsController.
public function openModalForm($sample_id) {
...
}
public function openModalForm($sample_id) {
$response = new AjaxResponse();
$form_state = new FormState();
$form_state->set('sample_id', $sample_id);
$modal_form = $this->formBuilder->buildForm(
SampleExtraOptionsForm::class,
$form_state
);
$response->addCommand(new OpenModalDialogCommand('Extra options', $modal_form, ['width' => '800']));
return $response;
}
AJAX: manage form in modal window
TODO:
Founder @
Co- Founder @
Vladyslav Moyseenko, a.k.a vlad.dancer
&
D8 School: DB, FAPI
By Vlad Moyseenko
D8 School: DB, FAPI
- 552