drupal 8
<?php
// Base de données.
$databases['default']['default'] = [
'host' => 'localhost',
'driver' => 'mysql',
'database' => '[DATABASE]',
'username' => '[USERNAME]',
'password' => '[PASSWORD]',
];
// URL en laquelle on a confiance.
$settings['trusted_host_patterns'][] = '^[XXX]\.nerocro\.fr$';
// Dossier des fichiers privés.
$settings['file_private_path'] = DRUPAL_ROOT . '/../drupal_private_files';
// Ne plus avoir de cache de rendu.
$settings['container_yamls'][] = __DIR__ . '/inc/development.services.yml';
$settings['cache']['bins']['render'] = 'cache.backend.null';
$settings['cache']['bins']['dynamic_page_cache'] = 'cache.backend.null';
// Pas de cache.
$config['system.performance']['cache']['page']['max_age'] = 0;
// Désactivation du cron.
$config['automated_cron.settings']['interval'] = 0;
// Afficher les erreurs.
$config['system.logging']['error_level'] = 'verbose';
// E-mail administrateur.
$config['system.site']['mail'] = 'nerocro@XXX.fr';
// Pas d'agrégation des fichiers statiques.
$config['system.performance']['css']['preprocess'] = FALSE;
$config['system.performance']['js']['preprocess'] = FALSE;
// Solr.
$config['search_api.server.solr_5']['backend_config']['connector_config']['host'] = 'localhost';
$config['search_api.server.solr_5']['backend_config']['connector_config']['port'] = '8983';
$config['search_api.server.solr_5']['backend_config']['connector_config']['core'] = 'CORENAME';
// $config['search_api.server.solr_5']['backend_config']['connector_config']['auth']['username'] = '';
// $config['search_api.server.solr_5']['backend_config']['connector_config']['auth']['password'] = '';
// Évite de modifier la production si je lance une indexation en local.
$config['search_api.index.default']['read_only'] = TRUE;
// Stage file proxy.
$config['stage_file_proxy.settings']['origin'] = '[URL_DEV]';
// Thème admin.
// $config['system.theme']['admin'] = 'seven';
$config['node.settings']['use_admin_theme'] = TRUE;
// Views.
$config['views.settings']['ui']['show']['master_display'] = TRUE;
$config['views.settings']['ui']['show']['advanced_column'] = TRUE;
$config['views.settings']['ui']['show']['display_embed'] = TRUE;
$config['views.settings']['ui']['show']['preview_information'] = TRUE;
$config['views.settings']['ui']['show']['performance_statistics'] = FALSE;
$config['views.settings']['ui']['show']['additional_queries'] = TRUE;
$config['views.settings']['ui']['show']['sql_query']['where'] = 'below';
$config['views.settings']['ui']['show']['sql_query']['enabled'] = TRUE;
$config['views.settings']['ui']['always_live_preview'] = TRUE;
$config['views.settings']['ui']['exposed_filter_any_label'] = 'new_any';
Url::fromRoute('entity.node.canonical', ['node' => 12])
Url::fromUri('https://aider.curie.fr/don/~mon-don/')
Url::fromUri('base://sites/default/files/2016-04/xxx.pdf')->toString()
file_create_url(public://2016-05/20140303_V2.pdf)
Url::fromRoute('<current>')->toString() // URL en cours
Drupal::request()->getUri() // URL en cours absolue
Url::fromRoute('<front>')->toString() // URL front
Url::fromRoute('<none>', NULL, ['fragment' => 'content']) // Pas de lien, juste une ancre
\Drupal::service('path.matcher')->isFrontPage(); // Est-ce la home ?
\Drupal::service('path.current')->getPath(); // La page actuelle ? (sans la langue)
\Drupal::routeMatch()->getRouteName(); // La route en cours ?
\Drupal::service('router.admin_context')->isAdminRoute($route); // Route admin ?
\Drupal::theme()->getActiveTheme()->getPath(); // Chemin du thème
\Drupal::routeMatch()->getParameter('node'); // Node en cours
// route:<none> dans un menu pour ne pas avoir de lien
// Redirection.
$response = new RedirectResponse(Url::fromRoute('view.recherche.recherche', $route_parameters)->toString());
$response->send();
// Construction d'une route : view.recherche.recherche : [nom_module].[id_vue].[id_display]
https://cryptic.zone/blog/drupal-8-cheatsheet-developers
$entity->entity; // Pour avoir l'entité enfant directement, si elle existe
$entity->field_XXX; // Pour avoir le field directement
// En fait, tout ce qui est dans values et properties est accessible directement (grâce à __get())
$entity->id(); // Son ID.
$entity->uuid(); // Son UUID.
$entity->getTitle(); // Son titre.
$entity->label(); // Le titre pour un terme plutôt.
$entity->toLink('...'); // Son lien.
$entity->toLink('...')->toRenderable(); // Pour éviter d'utiliser le thème link.
$entity->getEntityType()->id(); // Le nom machine du type de l'entité.
$entity->bundle(); // Son bundle.
$entity->isEmpty(); // Voir si le champ est rempli.
$entity->created->getString(); // La valeur d'un champ.
$entity->field_text->value; // La valeur d'un champ dans le cas d'un texte.
$entity->field_XXX->view([
'label' => 'hidden',
'type' => 'entity_reference_entity_view',
'settings' => ['view_mode' => 'cours_visuel'],
]); // Vue d'un champ.
$entity->getFileUri(); // L'URI d'un File. toLink ne fonctionne pas car cette classe n'a pas de canonical dans son annotation.
// Date.
$entity->field_date[0]->value // Date type 31/05/2017.
foreach ($entity->field_date[0] as $value) {
$value->getDateTime()->format('d m Y'); // Pour formater comme on veut.
$value->getDateTime()->getTimestamp(); // Pour avoir le timestamp.
}
$target_entity_type = 'media';
$labels = ['Grand carré', 'Petit carré'];
foreach ($labels as $label) {
$machine_name = strtolower($label);
$machine_name = \Drupal::transliteration()->transliterate($machine_name, 'fr');
$machine_name = preg_replace('/[^a-z0-9_]+/', '_', $machine_name);
\Drupal\Core\Entity\Entity\EntityViewMode::create(['targetEntityType' => $target_entity_type, 'id' => $target_entity_type . '.' . $machine_name, 'label' => $label])->save();
}
\Drupal\image\Entity\ImageStyle::create(['label' => 'XXX'])->save();
$field_XXX = $node->get('field_XXX')->getIterator()->current();
// Récupérer la clé sélectionnée.
$value = $node->field_XXX->target_id / value
// Récupérer la valeur sélectionnée.
$field_XXX->getPossibleOptions()[$value]
$field_XXX->getDataDefinition()->getLabel()
// Ne pas oublier de purger.
field_purge_batch(10);
// Si on veut contextualiser par la route.
// Faire une recherche dans le core pour avoir d'autres exemples de contexte.
$mon_entite->addCacheContexts(['route']);
\Drupal::service('date.formatter')->format(TIMESTAMP, 'jour_et_mois'),
$this->field_date->date->format('d m'),
$nids = \Drupal::entityQuery('node')
->condition('type', 'publication')
->condition('status', NODE_PUBLISHED)
->condition('promote', NODE_PROMOTED)
->condition('field_public.entity.tid', $tids, 'IN')
->condition('field_articles.target_id', $nid)
->condition('field_date_debut_fin.value', gmdate('Y-m-d'), '<=')
->sort('created', 'DESC')
->range(0, 10)
->pager(5)
->execute();
if (!empty($nids)) {
$nodes = Node::loadMultiple($nids);
}
$entities = Node::loadMultiple($ids);
// ou
$entities = \Drupal::entityTypeManager()->getStorage($entity_type)->loadMultiple($ids);
/** @var \Drupal\Core\Entity\EntityViewBuilderInterface $entity_type_manager */
$entity_type_manager = \Drupal::entityTypeManager()->getViewBuilder('node');
$items = $entity_type_manager->viewMultiple($entities, $view_mode);
// Old way.
/** @var \Drupal\node\NodeInterface $entities */
//foreach ($entities as $entity) {
// $items[] = $entity_type_manager->view($entity, 'teaser');
//}
$term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term'); // Pour connaître le parent
$term = Term::load($tid); // Charger un terme
$block = \Drupal\block\Entity\Block::load('[BLOCK_ID]');
$search_block = \Drupal::entityTypeManager()
->getViewBuilder('block')
->view($block);
---------------------
$search_block = \Drupal::entityTypeManager()
->getViewBuilder('block')
->lazyBuilder('[$build['#id']]', 'full');
--------------------- best way
return [
'#type' => 'view',
'#name' => 'recherche',
'#display_id' => 'tous_les_objets',
];
// Ca évite d'avoir à réellement créer une instance du block sans vraiment vouloir la placer et niveau cache c'est un p'tit peu mieux.
// foreach...
$items[] = [
'#markup' => 'TOTO',
'#wrapper_attributes' => ['class' => ['TOTO']],
];
$build['months'] = [
'#theme' => 'item_list',
'#items' => $items,
'#attributes' => [
'class' => 'actu-nav',
],
];
'left' => [
'#theme' => 'image',
'#uri' => theme_get_setting('logo')['path'],
'#width' => 80,
'#height' => 80,
],
[
'#type' => 'link',
'#title' => t('Ton lien'),
// '#title' => ['#markup' => [HTML]], // dans le cas où on veut mettre du HTML dans le lien
'#url' => Url::fromUri('XXX'),
],
[
'#type' => 'html_tag',
'#tag' => 'h2',
'#value' => $this->t(''),
],
\Drupal::formBuilder()->getForm('Drupal\XXX\Form\YYYForm')
Mieux vaut utiliser le type managed_file plutôt que file, il gère tout seul l'upload.
Lire l'annotation de MailManagerInterface.
$defaults = menu_ui_get_menu_link_defaults($node);
$menu_tree_parameters = new MenuTreeParameters();
$menu_tree_parameters->setRoot($defaults['id'])->excludeRoot();
$menu = \Drupal::menuTree()->load('', $menu_tree_parameters);
// -- Mieux :
// Lien en cours.
/** @var \Drupal\Core\Menu\MenuActiveTrail $menu_active_trail */
$menu_active_trail = \Drupal::service('menu.active_trail');
/** @var \Drupal\Core\Menu\MenuLinkInterface $current_menu */
$current_menu = $menu_active_trail->getActiveLink();
$current_id = $current_menu->getPluginId();
// Toute l'arborescence du menu du lien en cours.
$menu_tree = \Drupal::menuTree();
$menu_name = $current_menu->getMenuName();
// Je commence l'arborescence directement sur le node en cours.
$parameters = $menu_tree->getCurrentRouteMenuTreeParameters($menu_name);
$parameters->setRoot($current_menu->getPluginId())->excludeRoot();
$tree = $menu_tree->load($menu_name, $parameters);
// Transform the tree using the manipulators you want.
$manipulators = [
['callable' => 'menu.default_tree_manipulators:checkNodeAccess'],
// Only show links that are accessible for the current user.
['callable' => 'menu.default_tree_manipulators:checkAccess'],
// Use the default sorting of menu links.
['callable' => 'menu.default_tree_manipulators:generateIndexAndSort'],
];
$main_menu = $menu_tree->transform($tree, $manipulators);
if (!empty($defaults['entity_id'])) {
foreach ($menu as $value) {
$items[] = [
'#type' => 'link',
'#title' => $value->link->getTitle(),
'#url' => Url::fromRoute($value->link->getRouteName(), $value->link->getRouteParameters()),
];
}
$build['cens_standard_en_savoir_plus'] = [
'#theme' => 'item_list',
'#items' => $items,
];
}
// Sans node.
$parameters = new MenuTreeParameters();
$menu = \Drupal::menuTree()->load('entree-menu-4', $parameters);
// Créer les menus au préalable.
// A mettre dans un hook_update_N
// Lancer l'import avant pour avoir les menus de créée.
$menus = [
'footer-profils-fr' => [
'Grand public et donateurs' => [
['title' => "La recherche"],
],
'Patients et proches' => [
['title' => "Actualités"],
],
],
];
foreach ($menus as $menu_name => $menu) {
foreach ($menu as $level_one_title => $item) {
$first_level = MenuLinkContent::create([
'title' => $level_one_title,
'link' => ['uri' => 'internal:/node'],
'menu_name' => $menu_name,
'expanded' => TRUE,
'weight' => $counter++,
]);
$first_level->save();
foreach ($item as $level_two) {
MenuLinkContent::create([
'title' => $level_two['title'],
'link' => ['uri' => 'internal:/node'],
'parent' => $first_level->getPluginId(),
'menu_name' => $menu_name,
'weight' => $counter++,
])->save();
}
}
}
$filter = Drupal::service('plugin.manager.filter')->getInstance('[id_plugin_filter]');
$text = $filter->prepare($text);
$text = $filter->process($text);
$request = \Drupal::request();
$route_match = \Drupal::routeMatch();
$title = \Drupal::service('title_resolver')->getTitle($request, $route_match->getRouteObject());
S'il est lié à EntityReferenceFormatterBase alors, on utilise foreach ($this->getEntitiesToView($items, $langcode) as $delta => $file) {
sinon on utilise foreach ($items as $delta => $item) {
dans viewElements
$query->setOption('solr_param_mm', '75%');
// Configuration.
$this->configuration['fields']
// Le bundle.
$item->getDatasource()->getItemBundle($item->getOriginalObject())
// Drupal\Core\Entity\Plugin\DataType\EntityAdapter
$item->getOriginalObject()
// Drupal\media_entity\Entity\Media
$item->getOriginalObject()->getValue()
https://drupal-media.gitbooks.io/drupal8-guide/content/index.html
ENTITY MEDIA DOCUMENT
Création/modification de l'entité :
create
__construct
buildConfigurationForm
création du bundle :
create
__construct
thumbnail
Instanciation du média :
providedFields : retourne le nom des différentes propriétés (tableau)
getField : retourne les différentes propriétés (mime, size...)
Upload :
defaultConfiguration : configuration par défaut à l'ajout du widget sur EB
buildConfigurationForm : ça se passe dans l'ajout du widget, sert à afficher les deux champs location/extensions
getForm : affiche le form quand on clique sur l'onglet document
submit : gestion de la soumission du form au dessus
TEST:
$e = entity_load('media', 4);
d($e->getType());
d($e->getType()->providedFields());
d($e->getType()->getField($e, 'size'));
d($e->getType()->getField($e, 'mime'));
Par ordre de priorité.
\Drupal::XXX()
\Drupal::service()
Les deux font la même chose en gros.
Les classes de type "entity type" n'ont pas d'injection de dépendance.
'#cache' => [
'contexts' => [
'url',
'languages',
],
'tags' => $entity->getCacheTags(), // dans le cas où le bloc est sur une entité et dépend d'elle
'tags' => ['node_list'], // dans le cas où le bloc est dynamique par rapport à un CRUD d'un node
'tags' => ['menu_link_content_list'], // dans le cas où le bloc est dynamique par rapport à un CRUD d'un menu
],
../vendor/bin/drupal list
composer up --with-dependencies drupal/console
pour le mettre à jour en rc12 car drush bloque les autres versions dû à une dépendance avec symfony-console-completion, qui dépend de alchemy/zippy en 0.3 alors que console-core veur zippy 0.4