Magento 2 Request Flow In Depth

So far we have seen about the routers of magento but let’s understand the request flow by creating a simple controller, you can consider any existing controller and traverse through following steps by applying echo or var_dump. Lets start with our magento entry file

Index.php #39 
Code:-
/** @var \Magento\Framework\App\Http $app */
$app = $bootstrap->createApplication('Magento\Framework\App\Http');
$bootstrap->run($app);

Let us enter to our run function which is taking $app as parameter ($app is an instance of \Magento\Framework\App\Http). In bootstrap.php we have run function which launches the application.

class: \Magento\Framework\App\Http
public function run(AppInterface $application)
    {
        try {
            try {
                \Magento\Framework\Profiler::start('magento');
                $this->initErrorHandler();
                $this->initObjectManager();
                $this->assertMaintenance();
                $this->assertInstalled();
                $response = $application->launch();
                $response->sendResponse();
                \Magento\Framework\Profiler::stop('magento');
            } catch (\Exception $e) {
                \Magento\Framework\Profiler::stop('magento');
                if (!$application->catchException($this, $e)) {
                    throw $e;
                }
            }
        } catch (\Exception $e) {
            $this->terminate($e);
        }
    }

It time to go now to launch function in Magento\Framework\App\Http and check the code is calling dispatch method of frontcontroller, which is then calling match function of routers and as per our previous post we know our request will go to base router.

class: Magento\Framework\App\Http
$result = $frontController->dispatch($this->_request);

So we will be looking into Magento\Framework\App\Router\Base.php for match function, while looking closely to match function we can see it calls to matchAction and return its output.

class: Magento\Framework\App\Router\Base
public function match(\Magento\Framework\App\RequestInterface $request)
    {
        $params = $this->parseRequest($request);

        return $this->matchAction($request, $params);
    }

And here is the code of matchAction that we need to discuss:-

$actionInstance = $this->actionFactory->create($actionClassName);

$this->ActionFactory is an instance of Magento\Framework\App\ActionFactory and if we will look in create function, we have call to object manager which we know is responsible for creating instances.

class: Magento\Framework\App\ActionFactory
    public function create($actionName)
    {
…
        return $this->_objectManager->create($actionName);
    }
Now let’s see how objectmanager create an instance of every parameter in contructor

i.e, dependency injection in constructor.

Above $this->_objectManager is an instance of Magento\Framework\ObjectManager\ObjectManager. Here you can see the create function which is calling another create function:-

class: Magento\Framework\ObjectManager\ObjectManager
public function create($type, array $arguments = [])
    {
        $type = ltrim($type, '\\');
        //var_dump(get_class($this->_factory)); 
        return $this->_factory->create($this->_config->getPreference($type), $arguments);
    }


$this->_factory
is an object of Magento\Framework\ObjectManager\Factory\Dynamic\Developer class. Basically we have two factory class of object manager one is for production mode and another for development. If we were in producttion mode then $this->_factory will be an instance of Magento\Framework\ObjectManager\Factory\Dynamic\Production

In Developer .php we have create function which is getting the constructor parameter using line

$parameters = $this->definitions->getParameters($type);

$this->definition is an instance of Magento\Framework\ObjectManager\Definition\Runtime
And here in getParameters function we can see that parameters of constructor are being fetched one by one.

class: Magento\Framework\ObjectManager\Definition\Runtime
public function getParameters($className)
    {
        if (!array_key_exists($className, $this->_definitions)) {
            $this->_definitions[$className] = $this->_reader->getConstructor($className);
        }
        return $this->_definitions[$className];
    }

Going back to create function of Magento\Framework\ObjectManager\Factory\Dynamic\Developer, we have return statement as return $this->createObject($type, $args);. Here
$type = classname
$args = list of partameters

Now $this->createObject is an instance of Magento\Framework\ObjectManager\Factory\AbstractFactory

And here you can clearly see that objects are created in below function

class: Magento\Framework\ObjectManager\Factory\AbstractFactory
createObject($type, $args)
    {
        return new $type(...array_values($args));
    }

Magento 2 Routing

Routing is the most important part of any application or framework. This blogpost covers the request flow of magento or routing process in magento2. So lets start with our index.php which is an entry file for magento. So you can see the following code:-

$bootstrap->run($app);

Now moving on to run function of \Magento\Framework\App\Bootstrap see the below code:-

$response = $application->launch();
$response->sendResponse();

Here it calls the launch function of AppInterface which is impelmeented by Magento\Framework\App\Http, now lets look into the launch() function.

public function launch()
    {
        $areaCode = $this->_areaList->getCodeByFrontName($this->_request->getFrontName());
        $this->_state->setAreaCode($areaCode);
        $this->_objectManager->configure($this->_configLoader->load($areaCode));
        /** @var \Magento\Framework\App\FrontControllerInterface $frontController */
        $frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');
        $result = $frontController->dispatch($this->_request);
        // TODO: Temporary solution until all controllers return ResultInterface (MAGETWO-28359)
        if ($result instanceof ResultInterface) {
            $this->registry->register('use_page_cache_plugin', true, true);
            $result->renderResult($this->_response);
        } elseif ($result instanceof HttpInterface) {
            $this->_response = $result;
        } else {
            throw new \InvalidArgumentException('Invalid return type');
        }
        // This event gives possibility to launch something before sending output (allow cookie setting)
        $eventParams = ['request' => $this->_request, 'response' => $this->_response];
        $this->_eventManager->dispatch('controller_front_send_response_before', $eventParams);
        return $this->_response;
    }

Our function is first fetching the area code i.e, frontend or admin, then it sets the area code and configure it. Then we are calling dispatch function of Magento\Framework\App\FrontControllerInterface

$frontController = $this->_objectManager->get('Magento\Framework\App\FrontControllerInterface');
$result = $frontController->dispatch($this->_request);

Now lets look at dispatch method, similar to Magento1 it loops through all router.

/Magento/Framework/App/FrontController.php
class FrontController implements FrontControllerInterface
{
    public function dispatch(RequestInterface $request)
    {
        \Magento\Framework\Profiler::start('routers_match');
        $routingCycleCounter = 0;
        $result = null;
        while (!$request->isDispatched() && $routingCycleCounter++ < 100) {
            /** @var \Magento\Framework\App\RouterInterface $router */
            foreach ($this->_routerList as $router) {
                try {
                    $actionInstance = $router->match($request);
                    if ($actionInstance) {
                        $request->setDispatched(true);
                        $actionInstance->getResponse()->setNoCacheHeaders();
                        $result = $actionInstance->dispatch($request);
                        break;
                    }
                } catch (\Magento\Framework\Exception\NotFoundException $e) {
                    $request->initForward();
                    $request->setActionName('noroute');
                    $request->setDispatched(false);
                    break;
                }
            }
        }
        \Magento\Framework\Profiler::stop('routers_match');
        if ($routingCycleCounter > 100) {
            throw new \LogicException('Front controller reached 100 router match iterations');
        }
        return $result;
    }
}

$this->_routerList is coming from Magento\Framework\App\RouterList, if you will echo in getRouterInstance(), then you will get the list of all routers. (Note, try for page that does not exist so that all router name can be listed).
Below is the sequence of router and their class name respectively.

Standard - Magento\Framework\App\Router\Base
Urlrewrite - Magento\UrlRewrite\Controller\Router
Cms - Magento\Cms\Controller\Router
Default - Magento\Framework\App\Router\DefaultRouter

We will discuss these router in later part of post lets complete dispatch function first. Dispatch method loops through all router until any match is found or routingcyclecounter exceeds 100. Once any match is found request will be dispatched through that router and response will be shown accordingly.

Lets take a brief look on our routers responsibility now:-

Base or standard Router

This is located at Magento\Framework\App\Router\Base and is the first router in loop. Match() method will parse the request and will match the action using url(front name/action path/action/param 1/etc params/).

Url Rewrite Router

This is located in app/code/Magento/UrlRewrite/Controller/Router.php, if you look at match function then you can see the urlfinder which are fetching the entity-type and id from url key to generate required routing setting i.e, controller, action, and module. Once match is found these will be forwarded back to standard router for match.

Cms Router

It handles the cms request, it basically fetch the page id by using url-key and then set module name as cms, controller name as page and action as view i.e, app/code/Magento/Cms/Controller/Page/View.php controller. After setting these details rather than dispatching the request it break current loop and and start loop again to match it with base router.

Default Router

It is used when match is not found in any other router, used for 404 page error type request.

Performance Optimisation In Drupal

If your server has good configuration but your Drupal website is loading slow, you need to figure this out.

we need to care about speeding up Drupal application because, the speed of your website greatly affects your traffic, conversions, revenue, and even SEO rankings!

  • Shopzilla saw a 12% revenue increase after improving average page load times from 6 seconds to 1.2 seconds.
  • Google says they lose 20% of their traffic for each additional 100 milliseconds it takes a page to load. Speed matters. Google also incorporates your page-load time into your site’s search rankings.

Steps to speedup your Drupal website:

1. Always use latest version:

It is very important you are always running latest version of of drupal and it’s contributed modules, because drupal is an opensource CMS. Contributes always tries to optimise the things with latest security update. You can check the available update for drupal in reports menu on below path:

Home » Administration » Reports

It is showing that drupal core is not updated. We should not have such situation. We should always update drupal core as well as contributed modules.

2. Use caching mechanism :

Like other CMS drupal comes with some basic page caching and block cacking. You can use this caching by enabling this and set cache expiration time. you can find this under performance option.

Home » Administration » Configuration » Development

There are various cache modules available in drupal you can use those module Drupal modules for caching View caching modules is widely using. You can cache the views using this module. If you are using panels then you can also cache the panel itself.

Apart from above caching there are multiple cache available. You can configure all below caching mechanism and get speedup your website drastically

3. Content Delivery Network (CDN):

A content delivery network or content distribution network (CDN) is a globally distributed network of proxy servers deployed in multiple data centers. The goal of a CDN is to serve content to end-users with high availability and high performance. You can put you assets like js,css, image, video file on CDN.

Configure CDN is a easy task. I am explaining this little bit here and assuming that you are using CDN from Amazon.

  • Login to Amazon console.
  • Create a bucket.
  • create a cloud front for the same.

Download and configure CDN module

4. Gzip Compression:

Gzip is a method of compressing files (making them smaller) for faster network transfers. It is also a file format. Compression allows your web server to provide smaller file sizes which load faster for your website users. Enabling gzip compression is a standard practice. If you are running on Apache you can enable compression by adding the following to your .htaccess file.


  # Compress HTML, CSS, JavaScript, Text, XML and fonts
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddOutputFilterByType DEFLATE text/xml

  # Remove browser bugs (only needed for really old browsers)
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
  Header append Vary User-Agent

If you are running on Nginx You can enable compression by adding the following to your nginx.conf file.

gzip on;
gzip_comp_level 2;
gzip_http_version 1.0;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_disable "MSIE [1-6].(?!.*SV1)";
gzip_vary on;

Set Header Expiration time Expire headers tell the browser whether they should request a file from the server or grab it from the browser’s cache.


     ExpiresActive On
     ############################################
     ## Add default Expires header
     ## http://developer.yahoo.com/performance/rules.html#expires
     
     ExpiresDefault "access plus 1 year"
     
     

5. Use Lazy loading :

Lazy loading images dramatically increase your page load times by ensuring the image will only load when it is visible to the browser window. There is contributed modules available for Lazy loading

6. Compress js and css and use aggregation both:

You should compress and aggregate your JS and css it helps to increase the performance and reduce the page load time.

7. Uninstalled unused module :

You should uninstalled all those module that is not being use for the website.

8. view module vs custom Query :

If you application is very larger and you need to hit multiple view the it’s better to use custom query rather then using a view.

Magento 2:- Add a Grouped product programmatically

Follow my previous blogpost to create a simple product with magento that will give you a basic idea of creating products. In this blogpost we will continue from that post only. So to create product as grouped, we simply link some products to it.
In previous post code you also need to change type ID as grouped. Grouped product are added to link as related product are linked, below is the code that you need to add before saving product.

$childrenIds = array(53,54,55);
        $associated = array();
        $position = 0;
        foreach($childrenIds as $productId){
            $position++;
            //You need to load each product to get what you need in order to build $productLink
            $linkedProduct = $productRepository->getById($productId);
            
            /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */
            $productLink = $objectManager->create(\Magento\Catalog\Api\Data\ProductLinkInterface::class);

            $productLink->setSku('sku')
                ->setLinkType('associated')
                ->setLinkedProductSku($linkedProduct->getSku())
                ->setLinkedProductType($linkedProduct->getTypeId())
                ->setPosition($position)
                ->getExtensionAttributes()
                ->setQty(0);

            $associated[] = $productLink;
        }
        $product->setProductLinks($associated);

In below image you can see the data added to our product:-

Magento 2:- Add a bundled product programmatically

Follow my previous blogpost to create a simple product with magento that will give you a basic idea of creating products. In this blogpost we will continue from that post only. So to create product as bundled, we need to set two more attribute value i.e, price_view and price_type.
In previous post code you also need to change typeId as bundles. After creating a product with type bundled we have to add a link and option information for the product.
Firstly lets see the modified attribute:-

 $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_BUNDLE); 
 $product->setPriceType(1); 
 $product->setPriceView(1);

To add a link use the below code.

$link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterface::class);
$link->setPosition(0);
$link->setSku('MH01-XS-Orange');
$link->setIsDefault(false);
$link->getQty(1);
$link->setPrice(12);
$link->setPriceType(\Magento\Bundle\Api\Data\LinkInterface::PRICE_TYPE_FIXED);
 

To add link to option add below code:-

$optionRepository = $objectManager->create(\Magento\Bundle\Api\ProductOptionRepositoryInterface::class);
$option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterface::class);
$option->setTitle('Size');
$option->setType('radio');
$option->setRequired(true);
$option->setPosition(1);
$option->setProductLinks(array($link));
$optionRepository->save($product, $option);

In below image you can see the data added to our product:-

Magento 2:- Create a downloadable product programmatically

Follow my previous blogpost to create a simple product with magento that will give you a basic idea of creating products. In this blogpost we will continue from that post only. So to create product as downloadable, we need to set weight as NO and add details under downloadable Information tab.
In previous post code just set typeId as downloadable and product has weight to NO. After creating a product with type downloadable we have to add a link and sample data information for the product. To add a link use the below code.

$link_repository = $objectManager->create('Magento\Downloadable\Api\LinkRepositoryInterface');
$link_interface = $objectManager->create('\Magento\Downloadable\Api\Data\LinkInterface');
$link_interface->setTitle('first downloable product');
$link_interface->setPrice(9);
$link_interface->setNumberOFDownloads(10);
$link_interface->setIsShareable(1);
$link_interface->setLinkType('url');
$link_interface->setLinkUrl('http://www.w3solver.com');
$link_interface->setSampleType('url');
$link_interface->setSampleUrl('http://w3solver.com');
$link_interface->setIsUnlimited(0);
$link_interface->setSortOrder(0);
$link_repository->save('sku', $link_interface); // param1 is the sku of your product

To add data under sample section:-

$sample_repository = $objectManager->create('Magento\Downloadable\Api\SampleRepositoryInterface');
$sample_interface = $objectManager->create('\Magento\Downloadable\Api\Data\SampleInterface');
$sample_interface->setTitle('first downloable product');
$sample_interface->setSampleType('url');
$sample_interface->setSampleUrl('http://www.w3solver.com/download/qrcode.zip');
$sample_interface->setSortOrder(0);
$sample_repository->save('sku', $sample_interface);

In below you can see the data added to our product:-

Magento 2 Complete Guide to add a product programmatically

There are several scenario when we might need to add our product programmatically in Magento. This blog-post will provide you a detail guide to add the product in database programmatically.
You can follow below posts for creating different product of various type:-

Adding a simple product

Below code will add a new product to magento 2 with SKU as “W3PRO1”, comments are properly given to make the code self-explainable. We have added product with ‘default’ attribute set.

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance(); // instance of object manager
        $product = $objectManager->create('\Magento\Catalog\Model\Product');
        $product->setSku('W3PRO1'); // Set your sku here
        $product->setName('Sample Product'); // Name of Product
        $product->setAttributeSetId(4); // Attribute set id
        $product->setStatus(1); // Status on product enabled/ disabled 1/0
        $product->setProductHasWeight(1); // if product has weight
        $product->setWeight(10); // weight of product
        $product->setVisibility(4); // visibilty of product (catalog / search / catalog, search / Not visible individually)
        $product->setTaxClassId(0); // Tax class id
        $product->setTypeId('simple'); // Type of product (simple/virtual/downloadable/configurable)
        $product->setPrice(100);  // price of product
        $product->setStockData(
                     array(
                        'use_config_manage_stock' => 0,
                        'manage_stock' => 1,
                        'is_in_stock' => 1,
                        'qty' => 99
                         )
                     );
        $product->setNewsFromDate('11-11-2017'); // set the data from which product will be marked as new
        $product->setNewsToDate('11-12-2017'); // set the data till when product will be marked as new
        $product->setCountryOfManufacture('AL'); // Set country of manufacture

        $product->save();
Note: It is not recommended to create object using object manager, you should inject dependency through constructor and then further use them for object creation 

Add Related, Upsell and Crosssell to product

Above code is the basic example for adding product, now if we want to add related, upsell or crosssell product then we need to add below code before saving the products. Below we have just given example for related. Crosssell and upsell will also be created in the same way.

$this->_productLink = $objectManager->create('\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory ');
$skuLinks = '24-MB01,24-MB04,24-MB03';
 $skuLinks = explode(",",$skuLinks);
foreach($skuLinks as $skuLink) {
    $linkData = $this->_productLink->create();
    $linkData->setSku($product->getSku())
             ->setLinkedProductSku($skuLink)
             ->setLinkType("related");
    $linkDataAll[] = $linkData;
}
if($linkDataAll) {
   /* this will set related products detail, similarly we can add upsell and crossell */
   $product->setProductLinks($linkDataAll); 
}

Add Customizable Options

$this->_productCustomOption = $objectManager->create('\Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory');

$customOption = $this->_productCustomOption->create()->setTitle('Text')
                     ->setType('area')
                     ->setIsRequire(true)
                     ->setSortOrder(1)
                     ->setPrice(1.00)
                     ->setPriceType('fixed')
                     ->setMaxCharacters(50)
                     ->setProductSku($product->getSku());

$customOptions[] = $customOption;
$product->setOptions($customOptions);

Add website design, Schedule design update, gift options

$product->setWebsiteIds(array(1));  //add website id

/* Add design Attribute*/
$product->setPageLayout('1column');  
$product->setOptionsContainer('container1');
$product->setCustomLayoutUpdate('');

/* Add Schedule Design Update*/
$product->setCustomDesignFrom('1-6-2017');
$product->setCustomDesignTo('1-6-2017');
$product->setCustomDesign(1);
$product->setCustomLayout('1column');

/* Add Gift Options*/
 $product->setGiftMessageAvailable(1);

Magento 2 QRCode Generator extension

QR code (Quick Response Code) is the matrix barcode which is a machine-readable optical label that contains information about the item in our case it will have url of the products.

General Features of the extension

• One of the good marketing tool to drive sales and provides a modern image to your brand
• Enticing the mobile consumers by letting them simply scan the QR code and shop even on the go
• Incorporate QR code poster ads, in-store display, print ads etc

Feature List

– QR Codes for every Product Detail Page
– QR Codes list page in admin to generate mass Qrcode and print option
– No other plugins needed
– Qrcode can be generated for individual product edit page

Qrcode User Guide

1.) Once installed you can review the Qrcode menu under (product > Qrcode > List Qrcode) and view all product list with Qrcode details. List page is created to provide an option to mass generate Qrcode or print them.

2.) You can also generate Qrcode from product edit page. There is a tab of Qrcode and button provided separately for each product.

3.) On frontend product detail page, Qrcode is also available under Qrcode tab similar to review tab.

Versions: I’ve tested the module with the version 2.1.5

click link to download the extension

Let me know if you found any issue or have any query.

Magento 2:- Debugging and Customization of Mini Cart

I found lots of developer struggling out with customization of minicart in Magento 2, so thought to write this. Magento2 has modified things lots to render minicart using knockout js, template and layout xml. We will be going through debugging process step by step to understand more, drop in comments if you have any issue with any part.

Below you can see the image for minicart in magento 2:-

If you inspect the html code you will land up with something like this:-

From where does that “minicart-wrapper” comes, here we found it

vendor\magento\module-checkout\view\frontend\templates\cart.phtml

Let’s review layout file which is responsible to call this template:-

vendor\magento\module-checkout\view\frontend\layout\default.xml

<referenceContainer name="header-wrapper">
    <block class="Magento\Checkout\Block\Cart\Sidebar" name="minicart" as="minicart" after="logo" template="cart/minicart.phtml">
        <arguments>
            <argument name="jsLayout" xsi:type="array">
                <item name="types" xsi:type="array"/>
                    <item name="components" xsi:type="array">
                        <item name="minicart_content" xsi:type="array">
                            <item name="component" xsi:type="string">Magento_Checkout/js/view/minicart</item>
                            <item name="config" xsi:type="array">
                                <item name="template" xsi:type="string">Magento_Checkout/minicart/content</item>
                            </item>
                            <item name="children" xsi:type="array">
                                <item name="subtotal.container" xsi:type="array">
                                    <item name="component" xsi:type="string">uiComponent</item>
                                    <item name="config" xsi:type="array">
                                        <item name="displayArea" xsi:type="string">subtotalContainer</item>
                                    </item>
                                    <item name="children" xsi:type="array">
                                        <item name="subtotal" xsi:type="array">
                                            <item name="component" xsi:type="string">uiComponent</item>
                                            <item name="config" xsi:type="array">
                                               <item name="template" xsi:type="string">Magento_Checkout/minicart/subtotal</item>
                                            </item>
                                        </item>
                                   </item>
                                </item>
                                <item name="extra_info" xsi:type="array">
                                    <item name="component" xsi:type="string">uiComponent</item>
                                        <item name="config" xsi:type="array">
                                            <item name="displayArea" xsi:type="string">extraInfo</item>
                                        </item>
                                    </item>
                                    <item name="promotion" xsi:type="array">
                                        <item name="component" xsi:type="string">uiComponent</item>
                                        <item name="config" xsi:type="array">
                                            <item name="displayArea" xsi:type="string">promotion</item>
                                    </item>
                               </item>
                        </item>
                    </item>
                </item>
            </argument>
        </arguments>
        <container name="minicart.addons" label="Mini-cart promotion block"/>
    </block>
</referenceContainer>

We will be going through this layout xml step by step, lets understand below line


<block class="Magento\Checkout\Block\Cart\Sidebar" name="minicart" as="minicart" after="logo" template="cart/minicart.phtml">

So above line add a block with block class as Magento\Checkout\Block\Cart\Sidebar.php and template file path as

 Magento-Checkout/view/frontend/templates/cart/minicart.phtml

Let’s look at our template file minicart.phtml code to find “minicart-content-wrapper”class


<div id="minicart-content-wrapper" data-bind="scope: 'minicart_content'">
    <!-- ko template: getTemplate() --><!-- /ko -->
</div>

So we got our class, now check the statement getTemplate using knockout JS. From where does our template is now coming????? Oh, its time to go back and review default.xml once again and get the block components details(check for below code).


<item name="config" xsi:type="array">
    <item name="template" xsi:type="string">Magento_Checkout/minicart/content</item>
</item>

Above code provides the template details:-

Magento_Checkout/View/frontend/web/template/minicart/content.html

You can find your sidebar template here. We will be going in depth with items coming in sidebar (rest code will become quite easy for you to understand once we will cover items part). Check below code for this:-

<!-- ko if: getCartParam('summary_count') -->
    <strong class="subtitle"><!-- ko i18n: 'Recently added item(s)' --><!-- /ko --></strong>
    <div data-action="scroll" class="minicart-items-wrapper">
        <ol id="mini-cart" class="minicart-items" data-bind="foreach: { data: getCartParam('items'), as: 'item' }">
            <!-- ko foreach: $parent.getRegion($parent.getItemRenderer(item.product_type)) -->
                <!-- ko template: {name: getTemplate(), data: item, afterRender: function() {$parents[1].initSidebar()}} --><!-- /ko -->
            <!-- /ko -->
        </ol>
    </div>
    <!-- /ko -->

Above code has ordered list to show item recursively and data is being fetched using foreach loop of knockout.js

foreach: { data: getCartParam('items'), as: 'item' }

From where can I get this data in foreach, this question might be coming to your mind…?.. Lets discover it; where can it be? The answer can be found in default.xml, check below line of code:-

Magento_Checkout/js/view/minicart

So here we got the path of JS from where we can check about data..
Path to js file:-

Magento_Checkout/view/frontend/web/js/view/minicart.js

As you can see we have a function getCartParam(‘items’) in foreach, this function can be found in line 150,

	getCartParam: function (name) {
            if (!_.isUndefined(name)) {
                if (!this.cart.hasOwnProperty(name)) {
                    this.cart[name] = ko.observable();
                }
            }

            return this.cart[name]();
        }

This function gets the value from cart variable, which is getting its value set in update function

update: function (updatedCart) {
            _.each(updatedCart, function (value, key) {
                if (!this.cart.hasOwnProperty(key)) {
                    this.cart[key] = ko.observable();
                }
                this.cart[key](value);
            }, this);
        },

Update function is called in initialize(), and passing cartData() as a parameter, cartData is getting its value from customerData.get(‘cart’) i.e, we now need to check for customerData object get() function.

initialize: function () {
            var self = this,
                cartData = customerData.get('cart');
            this.update(cartData());
……..

CustomerData is being set using ‘Magento_Customer/js/customer-data’. Before we proceed a quick idea about define function. This function is from requireJs – first parameter of “define” function is array of dependency and second parameter is definition of our function. Definition function should always return an object. So now lets look at

Magento_Customer/view/frontend/web/js/customer-data.js

This file is responsible for sending ajax request to get data. Lets traverse through its code one by one. As mentioned above we have to reach customerData.get() , check below code in this file for the same:-

get: function (sectionName) {
            return buffer.get(sectionName);
        },

Now as we can see it is calling buffer.get(), so lets move to that code:-

get: function (sectionName) { 
            if (!this.data[sectionName]) {
                this.bind(sectionName);
            }

            return this.data[sectionName];
        },

Here code is calling bind() function which is setting value in data model:-

bind: function (sectionName) {
            this.data[sectionName] = ko.observable({});
        },

Now if you check customer.init() function there is a check for needReload(), which tells if we need reload or data should come from cache directly. Here we are either calling this.reload() if reload is needed or we are getting data from cache dataProvider.getFromStorage(), no need to reload here if keys validated properly.

Let check the reload function which is calling dataProvider.getFromServer() function and that is sending ajax request to get customer data:-

reload: function (sectionNames, updateSectionId) {
            return dataProvider.getFromServer(sectionNames, updateSectionId).done(function (sections) {
                buffer.update(sections);
            });
        },

Now check the getfromServer(), here you can see an ajax call.

            return $.getJSON(options.sectionLoadUrl, parameters).fail(function (jqXHR) {
                throw new Error(jqXHR);
            });

You must be thinking we have jumped from this.data[sectionName] = ko.observable({}); directly to customerData.init(). As we can see we are observing the data value here, so we understand the code which is responsible for providing changed value to this variable. There is one more code responsible for fetching data i.e, calling reload function

$(document).on('ajaxComplete', function (event, xhr, settings) {
        var sections,
            redirects;

        if (settings.type.match(/post|put/i)) {
            sections = sectionConfig.getAffectedSections(settings.url);

            if (sections) {
                customerData.invalidate(sections);
                redirects = ['redirect', 'backUrl'];

                if (_.isObject(xhr.responseJSON) && !_.isEmpty(_.pick(xhr.responseJSON, redirects))) {
                    return;
                }
                customerData.reload(sections, true);
            }
        }
    });

Enough of this, now lets get back to our content.html, so far we understand from where data is coming in foreach, now look at the inner foreach:-

foreach: $parent.getRegion($parent.getItemRenderer(item.product_type))

item.product_type => coming from loop
$parent.getItemRenderer => it means getItemRenderer() function of parent js file i.e, minicart.js

If you do console.log(($parent.getItemRenderer(item.product_type)), then you will get the name of displayArea to be shown. Like:- defaultRenderer

Now look into checkout_cart_sidebar_item_renderers.xml, here we have code of our block ‘minicart’, we have our region as seen in below code:-


<item name="itemRenderer" xsi:type="array">
    <item name="default" xsi:type="string">defaultRenderer</item>
    <item name="simple" xsi:type="string">defaultRenderer</item>
    <item name="virtual" xsi:type="string">defaultRenderer</item>
</item>

Just check below line to get the template of items of minicart.


<item name="displayArea" xsi:type="string">defaultRenderer</item>
<item name="template" xsi:type="string">Magento_Checkout/minicart/item/default</item>

So, we got our template file Magento_Checkout/view/frontend/web/template/minicart/item/default.html

I think that is enough for now and will help you a lot to debug and understand the code flow.

Field template in Drupal.

templating

What is field templating

Some time we need to change the layout/design of a field. We can create a complete node–contetntype.tpl But it is not the best practice. If we need to design a single field the we need to create a field template file.

How to do this???

Suppose we have a field departments and user can be select multiple departments and we need to display this departments field in a table format with some different styles. Then we need to create a field template file.

How to do this

We need to create a file under theme folder i.e. project_name/sites/all/themes/theme_name/ .

What should be the name of this file.

we will have to create a file with fiels–field_name.tpl.php. Suppose my field name is ‘field-department-list‘ then my file name will be field–field-department-list.tpl.php and the complete path for this file will be project_name/sites/all/themes/theme_name/field–field-department-list.tpl.php

<?php if (!$label_hidden): ?>
    <div class="field-label"<?php print $title_attributes; ?>><h4>Department Info</h4></div>
  <?php endif; ?>
<table class="field-group-format group_additional">
  <thead>
    <tr>
      <th>Field</th>
      <th>Value</th>
    </tr>
  </thead>
  <tbody>

  <div class="field-items"<?php print $content_attributes; ?>>
    <?php foreach ($items as $delta => $item): ?>

<tr>
    <th class="field-label">Department</th>
    <td class="field-items">
      <div class="field-item <?php print $delta % 2 ? 'odd' : 'even'; ?>"<?php print $item_attributes[$delta]; ?>><?php print render($item); ?></div>
    </td>
    </tr>
  <?php endforeach; ?>
</div>
  </tbody>
  </table>