Create custom module for render custom forms through a controller in Drupal 8 - drupal-8

I need to render a custom form which is created using Drupal\Core\Form\FormBase and Drupal\Core\Form\FormStateInterface through a controller in custom Drupal 8 module. Is there any guidence or reference to follow to do this?
Actually I tried to render form directly and through a controller. But both ways are not working. Only render the submit button. I refer the drupal 8 documentation also. But I couldn't find a solution for this. Please be kind enough to find my coding samples below. If there are anything wrong. Please correct me.
my_module.routing.yml
partner.content:
path: '/partner'
defaults:
_controller: '\Drupal\partner\Controller\PartnerController::add'
_title: 'Add Partner'
requirements:
_permission: 'access content'
partner.addform:
path: '/partner/add'
defaults:
_form: '\Drupal\partner\Form\AddForm'
_title: 'Add Partner'
requirements:
_permission: 'access content'
AddForm.php
namespace Drupal\my_module\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class AddForm extends FormBase
{
/**
* Returns form id
*
* #return string
*/
public function getFormId(): string
{
return 'my_module_add_form';
}
/**
* Build form array
*
* #param array $form
* #param FormStateInterface $formState
* #return array
*/
public function buildForm(array $form, FormStateInterface $form_state): array
{
// First name
$form['first_name'] = [
'#type' => 'textField',
'#title' => t('First Name'),
'#required' => true,
];
// Other input fields...
$form['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Save Changes'),
'#button_type' => 'primary',
);
return $form;
}
public function validateForm(array &$form, FormStateInterface $form_state) {}
public function submitForm(array &$form, FormStateInterface $form_state) {}
}
MyModuleController.php
<?php
namespace Drupal\my_module\Controller;
use Drupal\Core\Controller\ControllerBase;
use Drupal\my_module\Form\AddForm;
class MyModuleController extends ControllerBase
{
public function add()
{
$addForm = new AddForm();
$form = \Drupal::formBuilder()->getForm($addForm);
return [
'#theme' => 'form_my_module_add',
'#form' => $form,
];
}
}

Happy to find out the solution with Hemantha Dhanushka on my comment.
To make it clear this question has a correct answer, here I past the validated comment.
I would recommend you to use the first approach (using routing::_form instead
of Controller). Also, it seems you use the wrong #type for your
first_name field. Try textfield instead of textField.
Also, for people who want to go further, here are some links to implement a proper
routing::_form approach to expose a form as a page instead of using a Controller: https://www.valuebound.com/resources/blog/step-by-step-method-to-create-a-custom-form-in-drupal-8.
For people looking for more help about existing Form Element Reference (textfield, checkboxes, entity_autocomplete, ...) here is an excellent up-to-date article https://drupalize.me/tutorial/form-element-reference?p=2766

You can use buildForm() method for it. Check below code example:
public function add()
{
$form_state = new Drupal\Core\Form\FormState();
$form_state->setRebuild();
$form = \Drupal::formBuilder()->buildForm('Drupal\my_module\Form\AddForm', $form_state);
return [
'#theme' => 'form_my_module_add',
'#form' => $form,
];
}
Reference: https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Form!FormBuilder.php/function/FormBuilder::getForm/8.2.x

Related

Undefined function 'field_widget_instance

Getting error in Drupal 9 Migration custom module
function sun_link_field_process($element, $form_state, $complete_form) {
$instance = field_widget_instance($element, $form_state);
$settings = $instance['settings'];
This is Drupal 7 field API, it just needs converting to D9.x. Note too, it's very different now and needs to be in a class and use Annotations to be defined properly.
I see someone called "samtech" asked about this exact same function a couple of days ago;
function sun_link_field_process($element, $form_state, $complete_form) {
$instance = **field_widget_instance**($element, $form_state);
$settings = $instance['settings'];
$attributes = isset($element['#value']['attributes']) ? $element['#value']['attributes'] : $settings['attributes'];
$element['attributes']['link_classes'] = array(
'#type' => 'textfield',
'#title' => t('Custom link classes'),
'#description' => t('A space delimited list of custom classes to be applied to the link.'),
'#default_value' => isset($attributes['link_classes']) ? $attributes['link_classes'] : '',
'#field_prefix' => 'class="',
'#field_suffix' => '"',
);
return $element;
}
Assuming this is the full function, just look to /core/modules/image/src/Plugin/Field/FieldWidget/ImageWidget.php for how to apply a "process" on a form widget element in D9. But note, that your function exists at all suggests that none of the rest of the field is defined correctly either?
/**
* Form API callback: Processes an image_image field element.
*
* Expands the image_image type to include the alt and title fields.
*
* This method is assigned as a #process callback in formElement() method.
*/
public static function process($element, FormStateInterface $form_state, $form) {

Adding JS to field widget being created in my module - Drupal 8

Cross-posting to drupal.stackexchange.com
I am creating a custom field to eventually be displayed in a custom paragraph. I need to upload a JS file for the widget view, but can't seem to get it to work. Can anyone see what I am doing wrong or need to do differently?
I can add the field to the paragraph, add the paragraph to a document and see the fields, but I see no evidence of the JS being attached (the file is not downloaded in the browser and does not activate).
Any help or suggestions are appreciated.
file: src/Plugin/Field/FieldWidget/get_libguides_listings_widget.php:
<?php
namespace Drupal\get_libguides_listings\Plugin\Field\FieldWidget;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;
class get_libguides_listings_widget extends WidgetBase {
/**
* {#inheritdoc}
*/
public function formElement(
FieldItemListInterface $items,
$delta, array $element, array &$form,
FormStateInterface $form_state) {
$element['Subject_IDs'] = [
'#type'=>'textfield',
'#title'=>$this->t('Subject IDs to Display'),
'#description'=>$this->t('BLAH'),
'#default_value'
=>isset($items->getValue()[$delta]['Subject_IDs'])
?$items->getValue()[$delta]['Subject_IDs']
:'',
'#states'=>[
'visible' => [
[':input[name$="default_value_input[field_libguides_listing][0][SearchBy]"]'
=>['value'=>'subject']],
'or',
[':input[name$="default_value_input[field_libguides_listing][0][SearchBy]"]'
=>['value'=>'both']],
],
],
];
$element['Subject_IDs']['#attached'][]
= 'get_libguides_listings/get_searchby';
return $element;
}
}
file: get_libguides_listings.libraries.yml:
get_searchby:
js:
js/get_searchby.js: {}
dependencies:
- core/jquery
- core/drupal
- core/drupalSettings
file: js/get_searchby.js
/**
* #file
*/
(function(){
alert('hello there');
(function ($, Drupal)
{
Drupal.behaviors.get_searchby = {
attach: function (context, settings)
{
alert('hello');
}
};
}(jQuery, Drupal));
}());
Turns out I forgot the 'library' key $element['Subject_IDs']['#attached']['library'][] = ...

Retrieve a taxonomy term in the buildrow function of a drupal 8 custom entity

I have built a custom entity that works well. One of my fields is a taxonomy but I can not retrieve the name of the term in the buildRow(EntityInterface $entity) function which displays my records.
For a simple string field I do: $row['foo'] = $entity->foo->value;
How to do a taxonomy term that is an entity_reference: $row['bar'] = $entity->BAR_TERM_NAME;
Thank you for your help.
To work as requested you need 3 things:
Implements an entity_reference field in your custom Entity.
Add a getter methode for you field.
Retrieve your field in your custom ListBuilder -> buildRow().
Check the Drupal 8 documentation about FieldTypes, FieldWidgets and FieldFormatters.
Implements an entity_reference field
Your field foo in your Entity should be generated using the entity_reference field type.
public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
// Some code ...
$fields['foo'] = BaseFieldDefinition::create('entity_reference')
->setLabel($this->t('Foo field'))
->setDescription($this->t('The Foo field.'))
->setSetting('target_type', 'taxonomy_term')
->setSetting('handler', 'default')
->setSetting('handler_settings', ['target_bundles' => ['vocabulary_id' => 'vocabulary_id']])
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'vocabulary_id',
'weight' => 0,
])
->setDisplayOptions('form', [
'type' => 'options_select',
'weight' => 40,
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
// Some code ...
}
You should then replace the 3 vocabulary_id by the vocabulary that you wanna links.
Add a getter
In the same Class as your baseFieldDefinitions.
// Some code ...
public function getFoo() {
return $this->get('foo')->value;
}
// Some code ...
Retrieve the field
In your ListBuilder Class.
public function buildRow(EntityInterface $entity) {
// Some code ...
$row['foo'] = $entity->getFoo();
// Some code ...
}
Hopes it will help you !

Hook a twig template to a block in Drupal 8

I created a module which creates a custom block :
<?php
/**
* Provides a 'SLS Block' Block
*
* #Block(
* id = "SLS-Subheader",
* admin_label = #Translation("SLS Subheader"),
* )
*/
namespace Drupal\subheader\Plugin\Block;
use Drupal\Core\Block\BlockBase;
class SubheaderBlock extends BlockBase {
/**
* {#inheritdoc}
*/
public function build() {
return array(
'#title' => "test",
);
}
}
?>
The module name is "subheader"
In my subheader.module i want to hook a specific template:
<?php
/**
* Implements hook_theme().
*/
function subheader_theme() {
return array(
'slssubheader' => array(
'variables' => array('pierre' => NULL),
'template' => 'specifictemplate',
),
);
}
I tried all kind of naming convention for the function name and the array key, but always unsuccesful. It never hook the template to specifictemplate.html.twig
Anyone has an idea??
Thanks a LOOOOTTT
Pierre
I had the same problem, though probably a different cause. Google lead me to your question though. The issue with your code is the missing #theme key in your build method I believe:
public function build() {
return array(
'#title' => "test",
'#theme' => 'slssubheader' // this one
);
}
In my case I had to search for a couple of hours before I found out I accidentally added a custom namespace to my .module file. Drupal doesn't like that and didn't recognize any of my hooks.

Accessing Model in CakePHP Controller Test

I'm new to CakePHP, and I just started writing my first tests. Usually doing Ruby on Rails, my approach to testing a Controller::create action would be to call the create action, and then comparing the number of models before and after that call, making sure it increased by one.
Would anyone test this any other way?
Is there an easy (builtin) way to access models from a ControllerTest in CakePHP? I couldn't find anything in the source, and accessing it through the Controller seems wrong.
I ended up doing something like this:
class AbstractControllerTestCase extends ControllerTestCase {
/**
* Load models, to be used like $this->DummyModel->[...]
* #param array
*/
public function loadModels() {
$models = func_get_args();
foreach ($models as $modelClass) {
$name = $modelClass . 'Model';
if(!isset($this->{$name})) {
$this->{$name} = ClassRegistry::init(array(
'class' => $modelClass, 'alias' => $modelClass
));
}
}
}
}
Then my tests inherit from AbstractControllerTestCase, call $this->loadModels('User'); in setUp and can do something like this in the test:
$countBefore = $this->UserModel->find('count');
// call the action with POST params
$countAfter = $this->UserModel->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
Note that I'm new to CakePHP but came here with this question. Here's what I ended up doing.
I got my idea from #amiuhle, but I just do it manually in setUp, like how they mention in the model tests at http://book.cakephp.org/2.0/en/development/testing.html.
public function setUp() {
$this->Signup = ClassRegistry::init('Signup');
}
public function testMyTestXYZ() {
$data = array('first_name' => 'name');
$countBefore = $this->Signup->find('count');
$result = $this->testAction('/signups/add',
array(
'data' => array(
'Signup' => $data)
)
);
$countAfter = $this->Signup->find('count');
$this->assertEquals($countAfter, $countBefore + 1);
}
I am not sure why it is necessary to test how many times a model is called or instantiated from the controller action.
So, if I was testing Controller::create... my ControllerTest would contain something like:
testCreate(){
$result = $this->testAction('/controller/create');
if(!strpos($result,'form')){
$this->assertFalse(true);
}
$data = array(
'Article' => array(
'user_id' => 1,
'published' => 1,
'slug' => 'new-article',
'title' => 'New Article',
'body' => 'New Body'
)
);
$result = $this->testAction(
'/controller/create',
array('data' => $data, 'method' => 'post')
);
if(!strpos($result,'Record has been successfully created')){
$this->assertFalse(true);
}
}
The main things you want to test for is whether you are getting the right output for the input. And you can use xDebug profiler to easily find out what classes get instnantiated in a particular action and even how many times. There is no need to test for that manually!