So I have a controller with a route already configured my action looks like this
/**
* List of brands
*
* #return array
*/
public function listAction()
{
$brandIds = \Drupal::entityQuery('node')
->condition('type', 'brand')
->sort('title', 'asc')
->execute();
return [
'addition_arguments' => [
'#theme' => 'page--brands',
'#brands' => is_array($brandIds) ? Node::loadMultiple($brandIds) : [],
'#brands_filter' => \Drupal::config('field.storage.node.field_brand_categories')->get()
]
];
}
I would like to use #brands and #brands_filter in my twig template theme file page--brands, but I never see it go through.
Can anyone help?
Thank you
UPDATE
Worked it out
In you modules my_module.module file add the following
function module_theme($existing, $type, $theme, $path)
{
return [
'module.brands' => [
'template' => 'module/brands',
'variables' => ['brands' => []],
],
];
}
In your controller use
return [
'#theme' => 'mymodule.bands',
'#brands' =>is_array($brandIds) ? Node::loadMultiple($brandIds) : []
]
This will inject the variable Hope this helps omeone else who has this problem, wish the docs were better :)
Please refer below sample code :
mymodule.module
<?php
/**
* #file
* Twig template for render content
*/
function my_module_theme($existing, $type, $theme, $path) {
return [
'mypage_template' => [
'variables' => ['brands' => NULL, 'brands_filter' => NULL],
],
];
}
?>
mycontorller.php
<?php
/**
* #file
* This file use for access menu items
*/
namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;
class pagecontroller extends ControllerBase {
public function getContent() {
return [
'#theme' => 'mypage_template',
'#brands' => 'sampleBrand',
'#brands_filter' => 'sampleBrands_filter',
];
}
}
Twig File Name inside templates folder - mypage-template.html.twig
Related
I am new in Drupal world and I'm trying to use the Drupal From API to create a contact form with Ajax validation.
I'm facing 2 issues:
My following form (see below) works well but only when the user is connected as administrator. When I am not logged in as an administrator, it does not work.
I also created a custom Block to display my Form, unfortunately the block does not appear when I am logged in.
I try to follow this guide whitout success: https://panshul1410.blog/2018/07/15/drupal-8-ajax-validations-for-custom-form/
Here is the form I created:
<?php
namespace Drupal\dalcom_contact\Form;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class DalcomContactForm extends FormBase {
/**
* {#inheritdoc}
*/
public function getFormId() {
return 'dlcm_cform';
}
public function buildForm(array $form, FormStateInterface $form_state, $params = NULL) {
// Disable caching.
$form['#cache']['max-age'] = 0;
// Disable browser HTML5 validation.
$form['#attributes']['novalidate'] = 'novalidate';
// This will generate an anchor scroll to the form when submitting.
$form['#action'] = '#dlcm_cform';
$form['mail_visitor'] = [
'#type' => 'email',
'#placeholder' => t('E-mail*'),
'#description' => 'Your mail',
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::mailValidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['message_visitor'] = [
'#type' => 'textarea',
'#placeholder' => t('Message*'),
'#description' => 'Your message',
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::messValidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['accept_box'] = [
'#type' => 'checkbox',
'#title' => $this
->t('I accept the CME terms of use'),
'#required' => TRUE,
'#ajax' => [
'callback' => 'Drupal\dalcom_contact\Form\DalcomContactForm::acceptboxalidateCallback',
'effect' => 'fade',
'event' => 'change',
'progress' => [
'type' => 'throbber',
'message' => NULL,
],
],
];
$form['candidate_copy'] = [
'#type' => 'checkbox',
'#title' => t('Send me a copy of my message.'),
];
$form['actions']['#type'] = 'actions';
$form['actions']['submit'] = [
'#type' => 'button',
'#value' => $this->t('Send'),
'#ajax' => [
'event' => 'click',
'progress' => [
'type' => 'throbber',
'message' => 'Sending...',
],
],
];
$form['#theme'] = 'dalcom_contact_theme';
return $form;
}
public function submitForm(array &$form, FormStateInterface $form_state) {
foreach ($form_state->getValues() as $key => $value) {
drupal_set_message($key . ': ' . $value);
}
}
public function mailValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (!$form_state->getValue('mail_visitor') || empty($form_state->getValue('mail_visitor'))) {
$text = 'No email registered';
$color = 'red';
}
elseif (!filter_var($form_state->getValue('mail_visitor'), FILTER_VALIDATE_EMAIL)) {
$text = 'Invalid email address';
$color = 'red';
}
else {
$text = 'Valid mail';
$color = 'green';
}
$ajax_response->addCommand(new HtmlCommand('#edit-mail-visitor--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-mail-visitor--description', 'css', ['color', $color]));
return $ajax_response;
}
public function messValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (!$form_state->getValue('message_visitor') || empty($form_state->getValue('message_visitor'))) {
$text = 'No messages written';
$color = 'red';
}
elseif (strlen($form_state->getValue('message_visitor')) < 6) {
$text = 'At least 7 characters';
$color = 'red';
}
else {
$text = 'Messages written';
$color = 'green';
}
$ajax_response->addCommand(new HtmlCommand('#edit-message-visitor--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-message-visitor--description', 'css', ['color', $color]));
return $ajax_response;
}
public function acceptboxValidateCallback(array &$form, FormStateInterface $form_state) {
$ajax_response = new AjaxResponse();
if (empty($form_state->getValue('accept-box'))) {
$text = 'You must accept our termes of use to continue';
$color = 'red';
}
$ajax_response->addCommand(new HtmlCommand('#edit-accept-box--description', $text));
$ajax_response->addCommand(new InvokeCommand('#edit-accept-box--description', 'css', ['color', $color]));
return $ajax_response;
}
}
It works very well. But Ajax validation only works when I am connected. When I am not logged in as an administrator, it does not work.
Here is the block to display the form in my footer.
<?php
namespace Drupal\dalcom_contact_block\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormInterface;
/**
* Provides a 'dalcom contact' block.
*
* #Block(
* id = "dalcom_contact_block",
* admin_label = #Translation("Dalcom Contact Block"),
* category = #Translation("Block du formulaire Dalcom Contact")
* )
*/
class DalcomContactBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
$form = \Drupal::formBuilder()->getForm('\Drupal\dalcom_contact\Form\DalcomContactForm');
return $form;
}
}
As explain upper, the block does not appear when I am logged in. I have access to the form only through the path I defined in module.routing.yml. And when it appears (so when I'm not logged in), Ajax doesn't work on this block form either.
Does anyone have any idea what could cause this?
Please help me.
Edited:
Here is the module.routing.yml file
dalcom_contact.form:
path: '/contact-us.html'
defaults:
_title: 'Contact Us'
_form: 'Drupal\dalcom_contact\Form\DalcomContactForm'
requirements:
_permission: 'access content'
block.info.yml
name: Dalcom Contact Block
type: module
description: Block du formulaire Dalcom Contact.
core: 8.x
package: Custom
dependencies:
- node
- block
Updated:
I notice that when the form does not appear (when I am connected), it appears in its place
<span data-big-pipe-placeholder-id="…"></span>
I've done some research on this, but I can't get out of it. Maybe this will help you to know what's going on.
I finally found the solution on the Drupal forum. I put it here, maybe it will help in the future a novice who will be in my case.
What was missing was simply a list of essential javascripts for anonymous users. It seems that at one time it wasn't necessary, but now we have to add them otherwise they wouldn't be loaded for anonymous users.
So what I needed to do was add this to my theme.libraries.yml file
my_scripts:
version: VERSION
js:
js/scripts.js: {}
dependencies:
- core/jquery
- core/drupal.ajax
- core/drupal
- core/drupalSettings
- core/jquery.once
An odd one. I'm testing a REST API using Codeception and Symfony4/Doctrine2.
If a test has a single call to $I->canSeeInRepository(...);, it works fine.
However, if I make a call to $I->grabEntityFromRepository(...); (which works fine) before making this call, the $I->canSeeInRepository(...); call fails.
It seems like some kind of Doctrine issue.
Can anybody shed some light? Many thanks.
/**
* #param ApiTester $I
*/
public function testConvertOfferToTemplate(ApiTester $I)
{
$I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded');
/** #var \App\ServiceProviderBundle\Entity\Offer $offer */
$offer = $I->grabEntityFromRepository(\App\ServiceProviderBundle\Entity\Offer::class, [
'notes' => 'SOME NOTES - Custom Offer final draft',
'dateArchived' => null,
]);
$I->sendPOST('/offer-templates', json_encode([
'name' => 'Codeception Created Template From Offer',
'offer_id' => $offer->getId(),
]));
$json = array(
'offer_template' =>
array(
'name' => 'Codeception Created Template From Offer',
'charge_period' => $offer->getChargePeriod(),
'charge_amount' => $offer->getChargeAmount(),
'charge_currency' => $offer->getChargeCurrency(),
'terms' => $offer->getTerms(),
'_embedded' =>
array(),
),
);
$I->seeResponseContainsJson($json);
$I->canSeeInRepository(\App\ServiceProviderBundle\Entity\OfferTemplate::class, [
'name' => 'Codeception Created Template From Offer', // FAILS
]);
}
/**
* #param ApiTester $I
*/
public function testOfferCreatedFromTemplate(ApiTester $I)
{
$I->canSeeInRepository(\App\ServiceProviderBundle\Entity\OfferTemplate::class, [
'name' => 'Codeception Created Template From Offer', // PASSES
]);
}
I've found a few tutorials on how to open a modal window using Drupal 8, not so hard:
// Add an AJAX command to open a modal dialog with the form as the content.
$response->addCommand(new OpenModalDialogCommand('Load Window', $modal_form, ['width' => '800']));
But now how do I programmatically close this window? Or more simply, I would like a "Cancel" button available at the bottom of the modal?
Not sure if this is the best way to do it, but if you make an ajax call to a method that calls the CloseModalDialogCommand() the modal will close.
The route:
#Close the modal form
product.closeProductModal:
path: '/close-modal-form'
defaults:
_controller: '\Drupal\product\Controller\ModalController::closeModalForm'
_title: 'Close modal'
requirements:
_permission: 'access content'
_role: 'administrator'
And then the controller:
Use Drupal\Core\Ajax\CloseModalDialogCommand;
class ModalController extends ControllerBase {
public function closeModalForm(){
$command = new CloseModalDialogCommand();
$response = new AjaxResponse();
$response->addCommand($command);
return $response;
}
}
Building on the previous answer, I built a form and added a submit and cancel button like this. In the module/src/Form/ModalForm.php file the buildform method looks like this:
class ModalForm extends FormBase {
public function buildForm(array $form, FormStateInterface $form_state, $options = NULL) {
$form['#prefix'] = '<div id="modal_example_form">';
$form['#suffix'] = '</div>';
$form['name'] = [
'#type' => 'textfield',
'#title' => $this->t('Name'),
'#size' => 20,
'#default_value' => 'Joe Blow',
'#required' => FALSE,
];
$form['email'] = [
'#type' => 'email',
'#title' => $this->t('Email'),
'#size' => 30,
'#default_value' => 'Joe#Blow.com',
'#required' => FALSE,
];
$form['actions'] = array('#type' => 'actions');
$form['actions']['send'] = [
'#type' => 'submit',
'#value' => $this->t('Submit me bebe'),
'#attributes' => [
'class' => [
'use-ajax',
],
],
'#ajax' => [
'callback' => [$this, 'submitModalFormAjax'],
'event' => 'click',
],
];
$form['actions']['cancel'] = [
'#type' => 'submit',
'#value' => $this->t('cancel'),
'#attributes' => [
'class' => [
'use-ajax',
],
],
'#ajax' => [
'callback' => [$this, 'closeModalForm'],
'event' => 'click',
],
];
$form['#attached']['library'][] = 'core/drupal.dialog.ajax';
return $form;
}
Here is the submit handler:
/**
* AJAX callback handler that displays any errors or a success message.
*/
public function submitModalFormAjax(array $form, FormStateInterface $form_state) {
$response = new AjaxResponse();
// If there are any form errors, re-display the form.
if ($form_state->hasAnyErrors()) {
$response->addCommand(new ReplaceCommand('#modal_example_form', $form));
}
else {
//Close the modal.
$command = new CloseModalDialogCommand();
$response->addCommand($command);
}
return $response;
}
and the cancel handler
/**
* #return \Drupal\Core\Ajax\AjaxResponse
*/
public function closeModalForm() {
$command = new CloseModalDialogCommand();
$response = new AjaxResponse();
$response->addCommand($command);
return $response;
}
I'm trying to use Doctrine2 with ZF3. All components have been installed with composer.
When I try to use an Entity I have an exception :
Doctrine\Common\Persistence\Mapping\MappingException
Class 'Application\Entity\Concours' does not exist
The exception is thrown when I use in the Controller's action :
$concours = $this->entityManager->getRepository(Concours::class);
I have the same problem if i use :
$entity = new Concours();
or
$entity = new \Application\Entity\Concours();
I really don't understand why...
Thanks for help...
My configuration :
config/local.php
use Doctrine\DBAL\Driver\PDOMySql\Driver as PDOMySqlDriver;
return [
'doctrine' => [
'connection' => [
'orm_default' => [
'driverClass' => PDOMySqlDriver::class,
'params' => [
'host' => '127.0.0.1',
'user' => 'xxxx',
'password' => 'xxxx',
'dbname' => 'goch',
],
],
],
],
];
config/modules.config.php
return [
'Zend\Cache',
'Zend\Form',
'Zend\InputFilter',
'Zend\Filter',
'Zend\Paginator',
'Zend\Hydrator',
'Zend\Router',
'Zend\Validator',
'DoctrineModule',
'DoctrineORMModule',
'Application',
];
For Application Module,
module/Application/config/module.config.php
namespace Application;
use Zend\Router\Http\Literal;
use Zend\Router\Http\Segment;
use Zend\ServiceManager\Factory\InvokableFactory;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
return [
'router' => [
'routes' => [
'home' => [
'type' => Literal::class,
'options' => [
'route' => '/',
'defaults' => [
'controller' => Controller\IndexController::class,
'action' => 'index',
],
],
],
'application' => [
'type' => Segment::class,
'options' => [
'route' => '/application[/:action]',
'defaults' => [
'controller' => Controller\IndexController::class,
'action' => 'index',
],
],
],
],
],
'controllers' => [
'factories' => [
Controller\IndexController::class => Controller\Factory\IndexControllerFactory::class,
],
],
'view_manager' => [
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => [
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
],
'template_path_stack' => [
__DIR__ . '/../view',
],
],
'doctrine' => [
'driver' => [
__NAMESPACE__ . '_driver' => [
'class' => AnnotationDriver::class,
'cache' => 'array',
'paths' => [__DIR__ . '/../src/Entity']
],
'orm_default' => [
'drivers' => [
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
]
]
]
]
];
My Controller (module/Application/src/Controller/IndexController.php) is :
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Doctrine\ORM\EntityManager;
use Application\Entity\Concours;
class IndexController extends AbstractActionController {
/**
* Entity manager.
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
// Constructor method is used to inject dependencies to the controller.
public function __construct($entityManager)
{
$this->entityManager = $entityManager;
}
public function indexAction() {
return new ViewModel();
}
public function concoursAction(){
$concours=array();
$concours = $this->entityManager->getRepository(Concours::class);
// Render the view template
return new ViewModel([
'concours' => $concours
]);
}
}
And the associated Factory
namespace Application\Controller\Factory;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Controller\IndexController;
/**
* This is the factory for IndexController. Its purpose is to instantiate the
* controller.
*/
class IndexControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container,
$requestedName, array $options = null)
{
$entityManager = $container->get('doctrine.entitymanager.orm_default');
// Instantiate the controller and inject dependencies
return new IndexController($entityManager);
}
}
All my Entities class files are in module/Application/src/Application/Entity/,
here is the Concours Entity Class:
<?php
namespace Application\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Concours
*
* #ORM\Table(name="Concours", uniqueConstraints={#ORM\UniqueConstraint(name="numero_UNIQUE", columns={"numero"})})
* #ORM\Entity
*/
class Concours
{
/**
* #var integer
*
* #ORM\Column(name="ref", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $ref;
...
}
Here is your problem:
All my Entities class files are in
module/Application/src/Application/Entity/
Zend 3 uses PSR-4 instead of PSR-0 which is considered as depracated. You can confirm it by checking composer.json file. You should see following declaration:
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/",
}
},
In PSR-0 if you define Foo\Bar namespace is achored in src/ it will look for class in src/Foo/Bar/{your_class}.php while in PSR-4 it will look in src/{your_class}.php.
So... to fix your problem. Move Concours entity from:
module/Application/src/Application/Entity/
to:
module/Application/src/Entity/
I have problem with template for my custom page in my module.
I use hook_theme() to define my twig file. And when I check in hook_theme_registry_alter() I see my new template file but when I try use it it is not working.
My code :
file: first.module
/**
* Implement hook_theme().
*/
function first_theme($existing, $type, $theme, $path) {
return array(
'testtwig' => array(
'template' => 'testtwig',
'variables' => array('test_var' => NULL),
),
);
}
Controller:
/**
* #file
* Contains \Drupal\first\Controller\FirstController.
*/
namespace Drupal\first\Controller;
use Drupal\Core\Controller\ControllerBase;
class FirstController extends ControllerBase {
public function content() {
return array(
'#theme' => 'testtwig',
'#test_var' => t('sss'), //$output,
);
}
}
Error:
Template "modules/custom/first/templates/testtwig.html.twig" is not
defined (Drupal\Core\Template\Loader\ThemeRegistryLoader: Unable to
find template "modules/custom/first/templates/testtwig.html.twig" in
the Drupal theme registry.).
//.module file
<?php
/**
* Implements hook_theme().
*/
function MODULE_theme($existing, $type, $theme, $path) {
return [
'site_framework_display' => [
'variables' => ['test_var' => NULL],
'template' => 'page--site-framework',
],
];
}
//Controller
<?php
namespace Drupal\MODULE\Controller;
use Drupal\Core\Controller\ControllerBase;
class MODULEController extends ControllerBase {
public function getVersion() {
return [
'#theme' => 'site_framework_display',
//'#test_var' => \DRUPAL::VERSION,
'#test_var' => 'hello guys'
];
}
}