How to Enable Error Log in Magento2.4

Errors are the part of developer coding journey and they also improve us as developer.

A good developer always read the error carefully and find the solution for the same so let’s see how we can see error log in Magento.

Where you can find the error log

The log files are located in the <magento-root>/var/log/Β folder.

By default, Magento2 writes to the debug log (<magento-root>/var/log/debug.log) when it is in default or develop mode, but not when it is in production mode.

Enable error log

Use the bin/magento setup:config:set --enable-debug-logging=true && bin/magento c:f command to change the default value.

Disable error log

Use the bin/magento setup:config:set --enable-debug-logging=false && bin/magento c:f command to change the default value

Before Magento 2.3.1 enable error log

Use the bin/magento config:set dev/debug/debug_logging 1 && bin/magento c:f command to change the default value

Happy debugging πŸ˜€

How To Additional Options In Cart Item – Magento2

If you want to show any additional information in cart item then following code will help you out.

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="checkout_cart_product_add_after">
        <observer name="set_additional_options"
        instance="Codedecorator\Learn\Observer\SetAdditionalOptions"/>
    </event>
</config>
namespace Codedecorator\Learn\Observer;

use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Serialize\SerializerInterface;

class SetAdditionalOptions implements ObserverInterface
{
    protected $request;
    private $serializer;

    public function __construct(
        RequestInterface $request,
        SerializerInterface $serializer
    )
    {
        $this->request = $request;
        $this->serializer = $serializer;
    }

    public function execute(EventObserver $observer)
    {
        $item = $observer->getQuoteItem();
        $post = $this->request->getPost();
		
        $additionalOptions = array();
        if ($additionalOption = $item->getOptionByCode('additional_options')) {
            $additionalOptions = $this->serializer->unserialize($additionalOption->getValue());
        }
        // check your custom condition
        if(isset($post['height'])){
			$price = 100;
            $additionalOptions[] = [
                'label' => 'Height',
                'value' => $post['height']
            ];
        }
         // Without any condition add option
         $additionalOptions[] = [
                'label' => 'CD',
                'value' => 'CD OPTION'
            ];

        if (count($additionalOptions) > 0) {
            $item->addOption(array(
                'product_id' => $item->getProductId(),
                'code' => 'additional_options',
                'value' => $this->serializer->serialize($additionalOptions)
            ));
        }
    }
}

Options will be shown on frontend side but wont show in admin order.

To set Additional in Order as well then go with following steps.

Append following code in events.xml that we have created

 <event name="sales_model_service_quote_submit_before">
        <observer name="order_add" instance="Codedecorator\Learn\Observer\SetAdditionalOptionsToOrder" />
 </event>
<?php

namespace Codedecorator\Learn\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\Serialize\SerializerInterface;

class SetAdditionalOptionsToOrder implements ObserverInterface
{
    private $serializer;

    public function __construct(
        SerializerInterface $serializer
    )
    {
        $this->serializer = $serializer;
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        try{

            $quote = $observer->getQuote();
            $order = $observer->getOrder();

            foreach ($quote->getAllVisibleItems() as $quoteItem) {
              $quoteItems[$quoteItem->getId()] = $quoteItem;
            }

            foreach ($order->getAllVisibleItems() as $orderItem) {

                $quoteItemId = $orderItem->getQuoteItemId();
                $quoteItem = $quoteItems[$quoteItemId];
                $additionalOptions = $quoteItem->getOptionByCode('additional_options');

                if(!is_null($additionalOptions)) {
                    $options = $orderItem->getProductOptions();
                    $options['additional_options'] = $this->serializer->unserialize($additionalOptions->getValue());
                    $orderItem->setProductOptions($options);
                }
            }
            return $this;

        }catch (\Exception $e) {
            
             // catch error if any
        
        }
      
    }
}

Happy coding πŸ™‚

System configuration in admin Magento2

System configuration mainly used as module configuration where the admin will set some configuration for specific modules like enable/disable the module. Get some input or selection of options like that we have a variety of field to be created in the configuration.

Where you will find it?
You will be able to find the module configuration in Magento 2 admin -> Stores(Menu) -> Configuration

All the system configuration will have three parts:

  1. Tab (It is left side the system configuration page. Which contains multiple sections of multiple modules)
  2. The section will contain the groups of configuration for the specific module
  3. Each group will contain fields for the configuration

Few basic attributes are used in all the elements of system configuration are:

  1. Id: unique ID of the element
  2. Translate: To tell Magento to translate the label of the element according to the language of the admin
  3. sortOrder: Position of the element.
  4. showInDefault: Do you want to show this element when an admin hasn’t selected any scope. (Global)
  5. showInWebsite: Do you want to show this element when admin select website (Website)
  6. showInStore: Do you want to show this element when admin select store view (Store View)

Above mentioned 3,4,5 point mainly useful when we want to allow admin customer to configure the module based on the scope.

SCOPE in configuration.

Store: It is configuration limited to the store view, which is often used to display
a store in multiple languages.
Website: Configuration is limited to the website.
Global: It applies to the entire installation.

For example enable/disable of module if we can showInDefault=1 , ShowIndWebsite=1 and ShowInStore=1 then will show this field in all scope. If make Show InDefault=0, ShowInWebsite and ShowInStore=1 then it will show field in default or global scope admin have to change the scope.

<system> 
     <tab id="codedecorator" translate="label" sortOrder="10">
       <label>Codedecorator</label> <!--Tab Name-->
     </tab>
     <section id="one" translate="label" sortOrder="130" showInDefault="1" showInWebsite="1" showInStore="1">
       <class>one-section</class> <!--  Class name to section -->
       <label>Hello World</label> <!--Label Of this section -->
       <tab>codedecorator</tab> <!-- It will tell which tab is linked with this section so it should match with tab id and also can be used to group multiple section -->
       <resource>Codedecorator_Learn::codedecorator_config</resource> <!--  It used in ACL -->
       <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>License Configuration</label>
                <!-- Field element has type attribute which decide the type of field. -->
                <field id="serial_key" translate="label" type="text" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Serial Key</label>
                    <backend_model>Codedecorator\Learn\Model\Config\Backend\Lookup</backend_model>
                    <validate>required-entry</validate>
                    <comment>Take serial key from Codedecorator</comment> <!--Give a comment to field -->
                </field>
                <field id="enable" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
                    <label>Module Enable</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
       </group>
    </section>
</system>

Source Model: Source is model to provide data to field like select and multiple select.
Backend Model: Backend model is mainly useful when want to take some action before saving the configuration. Like to check serial key correct or not before saving the configuration if wrong provides a message that is not correct.

Happy coding guys!

How to delete image or file in Magento2

When we are working on image or file upload functionality from frontend of Magento, we also allowing customer to upload another or update the image so that time we also have to delete previously upload the image or file as we can left those uploaded image or file left on server.

Following code will help you with that logic.

<?php
namespace Codedecorator\Learn\Controller\Index;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Filesystem\Driver\File;
use Magento\Framework\Filesystem;
use Magento\Framework\App\Filesystem\DirectoryList;

class Delete extends Action
{

    protected $_filesystem;
    protected $_file;

    public function __construct(
        Context $context,
        Filesystem $_filesystem,
        File $file
    )
    {
        parent::__construct($context);
        $this->_filesystem = $_filesystem;
        $this->_file = $file;
    }

    public function execute()
    {
        ........
        $fileName = "file or image name";// replace this with some codes to get the $fileName
        $mediaRootDir = $this->_filesystem->getDirectoryRead(DirectoryList::MEDIA)->getAbsolutePath();
        if ($this->_file->isExists($mediaRootDir . $fileName)) {
            $this->_file->deleteFile($mediaRootDir . $fileName);
        }
       ......
    }
}

Let’s us know if you need any issue or any query.

Happy coding guys!

How to create a new table using Declarative Schema( db_schema.xml) in Magento2

We all know about PHP script like InstallSchema.php (old way to create new table) to create new table but magento has introduced Declarative schema to create or maintain the tables using declarative schema xml.

Advantage of this db_schema.xml is to avoid the unnecessary version checking for create new columns or delete column for each table change. Let’s create one table

<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
   <table name="codedecorator_learn" resource="default" engine="innodb" comment="Codedecorator Learn">
      <column xsi:type="int" name="id" padding="10" unsigned="false" nullable="false" identity="true" comment="ID" />
      <column xsi:type="varchar" name="name" nullable="false" length="25" comment="Name" />
      <column xsi:type="varchar" name="email" nullable="false" length="25" comment="Email" />
      <column xsi:type="varchar" name="description" nullable="false" length="255" comment="Description" />
      <column name="created_at" nullable="false" xsi:type="datetime" default="CURRENT_TIMESTAMP" on_update="false"/>
      <column name="updated_at" nullable="true" xsi:type="datetime" default="CURRENT_TIMESTAMP" on_update="true"/>
      <constraint xsi:type="primary" referenceId="PRIMARY">
         <column name="id" />
      </constraint>
   </table>
</schema>

After creating db_schema.xml, we need to run following command to tell magento that we have created new table and also for backward compatibility with php script.

It will not directly delete any column or table if you dont have entry in whitelist because there might be upgrade schema available for the same so that it is important to generate whitelist.

php bin/magento setup:db-declaration:generate-whitelist --module-name=Codedecorator_Learn

Note: When you disable any module with db schema and you run setup upgrade command then it will delete the module table directly if you want to avoid that situation.

Please ran command using setup:upgrade --safe-mode=1 in order to create a database backup and then eventually setup:upgrade --data-restore=1 if you enable the module back and wish to restore from that backup.

Happy coding guys!

File Upload in System Configuration in Magento2

Following files and steps will help you to add file upload in system configuration with custom file type validation.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <tab id="codedecorator" class="code-config-tab"  translate="label" sortOrder="300"> 
            <label><![CDATA[Decorator Extensions]]></label> 
        </tab> 
        <section id="codedecorator_learn" translate="label" type="text" sortOrder="99" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Company Agreement</label>
            <tab>codedecorator</tab>
            <resource>Codedecorator_Learn::config</resource>
            <group id="general" translate="label" type="text" sortOrder="10" showInDefault="1" showInWebsite="0" showInStore="0">
                <label>General</label>
               <field id="custom_file_upload" translate="label" type="Magento\Config\Block\System\Config\Form\Field\File" sortOrder="6" showInDefault="1" showInWebsite="1" >
                <label>Upload custom file</label>
                <backend_model>Codedecorator\Learn\Model\Config\Backend\File</backend_model>
                <upload_dir config="system" scope_info="1">cdlearn</upload_dir>
            </field>
            </group>
        </section>
    </system>
</config>
<?php

namespace Codedecorator\LearnCompanyAccount\Model\Config\Backend;

class File extends \Magento\Config\Model\Config\Backend\File
{
    public function _getAllowedExtensions() {
        return ['pdf'];
       //return ['pdf','svg','jpeg'];
    }
}

We have requirement of PDF file only so we have pub/media/cdlearn/defaultkept pdf only if you have other extension to be checked or validate than just remove the comment. Uploaded file will be available in the pub/media/cdlearn/default folder

Magento 2 : Deprecated Functionality: Function ReflectionType::__toString() is deprecated

If you are stuck with above problem, we have solution for you which mentioned below.

File: vendor/zendframework/zend-code/src/Reflection/ParameterReflection.php
OR
File: vendor/laminas/laminas-code/src/Reflection/ParameterReflection.php

In function detectType() replace line return (string) $type; with return $type->getName();
File: vendor/magento/framework/DB/Sql/UnionExpression.php

In function __toString() replace line $sql = implode($parts, $this->type); with $sql = implode($this->type,$parts);
File: vendor/magento/framework/App/AreaList.php

In function getCodeByFrontName() replace line if ($areaInfo['frontName'] == $frontName) with if (isset($areaInfo) && $areaInfo['frontName'] == $frontName)

I hope this solution help you out and let’s know if you have any doubt or any other solution which worked for you.

Happy Coding!

How to add custom attribute to the body tag in Magento 2

You have already noticed attribute tag in layout xml and you are wondering what is doing. Let’s just see the customer_account.xml

    .....
    <head>
        <title>My Account</title>
    </head>
    <body>
        <attribute name="class" value="account"/>
        <attribute name="cd-attribute" value="cd-account"/>
       ........
    </body>
    .......

So in above example, 1st line will add attribute class with value account if class attribute already exists it will append the value to that attribute and 2nd line will add attribute called cd-attribute with value cd-account in body tag

I hope you liked the small content .

Happy coding!

How to enable error reporting in Magento 2

As developers, we always need to see the error while developing extensions or solving the bugs. Many times you just see the blank page on Magento and wonder what will be the issue.

In the default setting of Magento 2, the function which allows displaying the error on the frontend is disabled so here is the way to see the error and enable the error reporting in Magento2.

The number one thing that we always do as developers is enable the Developer mode on the following magento command

php bin/magento deploy:mode:set developer

if you are still unable to see the error then you just need to edit app/bootstrap.php(from root of your magento directory)

Find following the code in above file set as following

error_reporting(E_ALL); // Set Error Reporting as E_ALL (Report all PHP errors)

ini_set('display_errors', 1); // Uncomment this line to enable PHP error display

You will see all the errors on the browser now.

Happy Coding !

How to reload/refresh the quote using js in Magento2

We were working on custom discount module where it allows customers to use the points assigned by the admin on checkout(kind of rewards point in magento). To give discount on the applied discount, we need to reload the quote after applying discount. Following code snippets helped us to do so.

require(
    [
    'Magento_Checkout/js/model/quote',
    'Magento_Checkout/js/model/cart/totals-processor/default'
   ],
    function(
        quote,
        totalsDefaultProvider
    ) {
        totalsDefaultProvider.estimateTotals(quote.shippingAddress());
    }
);
Reload the quote using js

Let us know if you are trying achieve the same. We will guide you for the same.