Skip to main content

Drupal 10

Displaying 1 - 20 of 48

REACT: Controlled or Uncontrolled components

The form is one of the most-used HTML elements in web development. 
Since the introduction of React, the way forms have been handled has changed in many ways.
In React, there are two ways to handle form data in our components:
The first way is the Controlled Component
We handle form data by using the state within the component to handle the form data. 
The Second way is Uncontrolled Component:
We let the DOM handle the form data by itself in the component. 

Controlled Component

import React, { Component } from 'react';

class App extends Component {
    state = {
        message: ''
    }
    updateMessage = (newText) => {
        console.log(newText);
        this.setState(() => ({
            message: newText
        }));
    }
    render() {
        return (
            <div className="App">
                <div className="container">
                    <input type="text"
                        placeholder="Your message here.."
                        value={this.state.message}
                        onChange={(event) => this.updateMessage(event.target.value)}
                    />
                    <p>the message is: {this.state.message}</p>
                </div>
            </div>
        );
    }
}

PHP 8.3 Released!

PHP 8.3 is a major update of the PHP language.
It contains many new features, such as explicit typing of class constants, deep-cloning of readonly properties and additions to the randomness functionality. As always it also includes performance improvements, bug fixes, and general cleanup.

Messenger Api: How to set message

Drupal set message was deprecated in Drupal 8.5 and will be removed before Drupal 9. 
Time for a roundup of this new API and how to use it.

\Drupal::messenger()->addMessage('This is a regular message');
\Drupal::messenger()->addStatus('This is a status message, meaning status is OK or successful (green).');
\Drupal::messenger()->addError('This is an error message (red)');
\Drupal::messenger()->addWarning('This is a warning message (orange)');

Sending JSON with Basic Authentication Credentials

To post JSON to a server with Basic Authentication credentials, you need to make an HTTP POST or PUT request, include the JSON in the body of the HTTP message, and pass the "Authorization: Basic [token]" HTTP header to the server. 
The [token] is a Base64 encoded string of user credentials in the form of a login:password string. 
In this POST JSON with a Basic Authentication Credentials Example, we send a POST request with JSON body and "Authorization: Basic [token]" header to the ReqBin echo URL. 

<script>
      var USERNAME="admi";
      var PASSWORD="chanud";

      var person = {
        firstName:"tester2",
        lastName:"drupal",
        userName:"tester2drupal",
        eMail:"teter2@drupalvip.com",
        pass1:"teter2drupal",
        passConfirm:"teter2drupal",
        role:"Affiliate" 
      };
      
      $.ajax({
        type: "POST",
        url: 'https://mydomain/api/route',
        dataType: 'json',
        headers: {
         "Authorization": "Basic " + btoa(USERNAME + ":" + PASSWORD)
        },
        data: person,
        //data: JSON.stringify(person),
        success: function (data) {
          $("response").html(data.msg);
        },                
      });
    </script>

How To Attach Library To A Specific Content Type

If you need to upload a library with a module during its operation, in Drupal it's called attaching file.
Attaching a library can be done in several ways depending on your needs. 
Remember that the library is always registered by its module or theme name followed by the library name. 

DrupalVIP technical notebook & support

function rwcenter_page_attachments(array &$attachments) {
	$attachments['#attached']['library'][] = 'rwcenter/content';
        
    $node = \Drupal::routeMatch()->getParameter('node') ?? \Drupal::routeMatch()->getParameter('node_preview');
    if (is_null($node)) {}
    else {
    	if ($node->getType()=='rwcenter') {
        	$attachments['#attached']['library'][] = 'rwcenter/content';
        }
    }        
}

Creating a Block in Drupal 10 Programmatically

Drupal's great feature is Custom Block. blocks are easy and fast to set in any region, with Drupal9 you can even set the same block in a few regions.
There are a few technical options to create a block, here we will overview the programming option only.
so, what is a block?
Blocks are chunks of content with ID and classes which can be placed in manipulated within the page. 

namespace Drupal\my_module\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\Block\BlockPluginInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\UncacheableDependencyTrait;

/**
 * Provides a 'SetTask' Block.
 *
 * @Block(
 *   id = "dashboard_newtask_block",
 *   admin_label = @Translation("Dashboard New Task"),
 *   category = @Translation("DrupalVIP"),
 * )
 */
class NewTaskBlock extends BlockBase implements BlockPluginInterface {
    use UncacheableDependencyTrait;
    
    /**
    * {@inheritdoc}
    */
    public function build() {
        // Do NOT cache a page with this block on it.
        \Drupal::service('page_cache_kill_switch')->trigger(); 
        // build from form               
        $build = \Drupal::formBuilder()->getForm('Drupal\drupalvip_dashboard\Form\NewTaskForm');
        $build['#attributes']['class'][] = 'my_class';
        $build['#cache']['max-age'] = 0;
        $build['#cache']['contexts'] = [];
        $build['#cache']['tags'] = [];                   
        return $build;
    }       
  
    /**
    * {@inheritdoc}
    */
    public function blockForm($form, FormStateInterface $form_state) {
        $form = parent::blockForm($form, $form_state);
        $config = $this->getConfiguration();
        $form['block_note'] = [
            '#type' => 'textfield',
            '#title' => $this->t('Note'),
            '#description' => $this->t('block note '),
            '#default_value' => isset($config['block_note']) ? $config['block_note'] : '',
        ];
        return $form;
    }  

    /**
    * {@inheritdoc}
    */
    public function blockSubmit($form, FormStateInterface $form_state) {
        parent::blockSubmit($form, $form_state);        
        $values = $form_state->getValues();
        $this->configuration['block_note'] = $values['block_note'];
    }    
    
} // end of class

Custom Block: Create fast and simple

Blocks are individual pieces of your site’s web page layout. They are placed inside the regions of your theme, and can be created, removed, and rearranged in the Block layout (admin/structure/block) administration page.

Examples of blocks include the Who’s online listing, the main navigation menu, and the breadcrumb trail. The main page content is also a block.

<?php

namespace Drupal\basic_module\Plugin\Block;

use Drupal\Core\Block\BlockBase;

/**
 * Block annotation
 * 
 * @Block(
 *      id = "basic_block",
 *      admin_label = @Translation("Basic Block"),
 * )
 */
class BasicBlock extends BlockBase {
   /**
     * {@inheritDoc}
     */
    public function build() {
        $markup = '';
        $markup .= '<div>';
        $markup .= '    <p>Anything can come here: code, variables, html, etc.  </p>' ;
        $markup .= '</div>';
        return [
            '#type' => 'markup',
            '#markup' => $markup,
        ];
    }    
    
} // end of class

Success Message After Submitting Form

In building a custom form you must keep in mind a few issues:

elements, functionality, and response for best user experience 

DrupalVIP technical notebook & support

public function submitForm(array &$form, FormStateInterface $form_state) {
  $this->logger('user')->notice('Deleted %ip', ['%ip' => $this->banIp,]);
  $this->messenger()->addStatus($this->t('The IP address %ip was deleted.', [    '%ip' => $this->banIp,  ]));
  $form_state->setRedirectUrl($this->getCancelUrl());
}

Open Ajax Modal Dialog from Controller

Dialogs are often called dialog boxes, modal windows, or pop-up windows. 
Whatever you call them, they are a quick and easy way to display additional information without reloading the entire page. 
Dialog boxes can display just some static text, any node or form of your page, a views page, or any custom markup you'll feed them. 

DrupalVIP technical notebook & support

        public function requestResidenceUpload(Request $request): AjaxResponse {
            $arg = $request->get('arg1');
            
            // Add an AJAX command to open a modal dialog with the form as the content.      
            $response = new AjaxResponse();
            $modal_form = $this->formBuilder->getForm('Drupal\mymodule\Form\MyForm', $arg);
            $response->addCommand(new OpenModalDialogCommand('Upload', $modal_form, ['width' => 600, 'height'=>600]) );
            return $response;        
        } 

Drupal module info file

Drupal uses .info files to store metadata about themes and modules.
For modules, the .info file is used for:

  1.  Rendering information on the Drupal Web GUI administration pages;
  2.  Provide criteria to control module activation and deactivation;
  3.  Notifying Drupal about the existence of a module;
  4.  Specifying the module's dependencies on other Drupal projects
    for general administrative purposes in other contexts.

This .info file is required for the system to recognize the presence of a module.

name: Hello World Module
description: Creates a page showing "Hello World".
package: Custom

type: module
core_version_requirement: ^9.4 || ^10

dependencies:
  - drupal:link
  - drupal:views
  - paragraphs:paragraphs
  - webform:webform (>=6.1.0)

test_dependencies:
 - drupal:image

configure: hello_world.settings
configure_parameters:
  pluginId: hello_world_plugin

php: 8.0

hidden: true
required: true

# Set the module lifecycle status deprecated
lifecycle: deprecated
lifecycle_link: https://www.drupal.org/node/3223395#s-aggregator

# Note: do not add the 'version' or 'project' properties yourself.
# They will be added automatically by the packager on drupal.org.
# version: 1.0
# project: 'hello_world'

entityQuery intro and examples

A node can include a few fields.
Every field is a table in the database.
So If I need to find a specific node, doing it with SQL means doing complicated queries, which might have few joins and many conditions, The Drupal platform created a simpler way to deal with it: EntityQuery

DrupalVIP technical notebook & support

$query = \Drupal::entityQuery('node')
  ->condition('type', 'page')
  ->condition('field_some_field', 14)
  ->accessCheck(TRUE);
$results = $query->execute();

The node access system

All node access modules are queried using hook_node_grants() to assemble a list of "grant IDs" for the user.
This list is compared against the table. 
If any row contains the node ID in question (or 0, which stands for "all nodes"), one of the grant IDs returned, and a value of TRUE for the operation in question, then access is granted. 
Note that this table is a list of grants; any matching row is sufficient to grant access to the node.

DrupalVIP technical notebook & support

Fetch and display data from API in React js

When you develop an application, you will often need to fetch data from a backend or a third-party API. 
In this article, I will try to go through the process of fetching and displaying data from a server using React Fetch.

DrupalVIP technical notebook & support

import React, { useEffect, useState } from "react";

function handleClick() {
    alert('You clicked node ');
}

export default function RWTaskIssues({nodeid}) {        
    const FetchAPI = '/rwtask/issues?task=' + nodeid + '&op=get';
    console.log("api fetch: " + FetchAPI);
    
    const [issues, setIssues] = useState([]);
    const fetchData = () => {
        fetch(FetchAPI)
            .then(response => {
                return response.json();
            })
            .then(response => {
                console.log("response data: " + response.data.items);
                setIssues(response.data.items);
            });
    };

    useEffect( () => {
        fetchData();
    }, []) ;   
    
    console.log("issues data: " + issues);
    
    return (
        <div className="block block-layout-builder block-field-blocknoderwtaskfield-rwtask-issue">
            <h2 className="block-title">תיאור הבעיה</h2>
            <div className="block-content">               
                {issues.length > 0 && (
                    <div className="field field-name-field-rwtask-issue field-type-text-long field-label-hidden field-items">
                        {issues.map(item => (
                            <div key={item.key} className="field-item" dangerouslySetInnerHTML={{__html: item.value}} />
                        ) ) }
                    </div>
                )}
                <button onClick={handleClick}>
                    Edit
                </button>            
            </div>
        </div>
    );        
}