Aleksandar Krstic

Personal Blog

Laravel 5 – Display nested relations in View without Eloquent

In case that you need to display nested relations in a View, Laravel offers Eloquent.

This approach is well known and well documented in official Laravel Documentation.

So, we will play with different approach here.

First of all, what are nested relations?

We can use example with projects and tasks where you want to display all projects with their tasks.

Something like:

Project 1
Task 1
Task 2

Project 2
Task 3
Task 4

How to achieve this?

Step 1. Create function which will retrieve data from DB in your Controller
It’s usually something like app/Http/Controllers/YourController.php

    public function getProjects(){
        $data['data'] = DB::table('projects')
                        ->join('tasks', 'projects.id', '=', 'tasks.project_id')
                        ->select('projects.name as pname', 'projects.id as pid', DB::raw('group_concat(tasks.id SEPARATOR "<br>") as tid'), DB::raw('group_concat(tasks.name SEPARATOR "<br>") as tname'))
                        ->groupBy('pid')
                        ->get();
        return view('project-list', $data); //view where we will use this data
    }

First two lines of query are pretty much strait forward – it’s a simple join of two tables (projects and tasks).

In line with select part you can notice the following:

DB::raw('group_concat(tasks.id SEPARATOR "<br>")

This is standard Laravel way to achieve MySQL GROUP_CONCAT.

Why we need this? We need it in order to group tasks by Project. Otherwise, we will get something like:
PROJECT 1
Task 1
PROJECT 1
Task 2
PROJECT 2
Task 3
PROJECT 2
Task 4

With

SEPARATOR "<br>"

we will replace standard “,” separator with “new line” tag, just to look nicer.

Of course, we also need groupBy, and as I mentioned, we want to group it by Project (or better to say by Project’s ID).

Step 2. Routing
It’s usually in routes/web.php

Route::get('/project-list', 'YourController@getProjects');

Here we basically connect function with our View called “project-list”.

Step 3. Create View and display data
Views are usually under resources/views, and in that folder we will create project-list.blade.php in order to display data with standard foreach loop.

foreach ($data as $value) {
	echo "<div class='project-list-out'>";
	echo "<table class='project-list'>";
	echo "<tr>";
	echo "<td>" . $value->pname . "</td>";
	echo "</tr>";
	echo "</table>";

	echo "<table class='task-list'>";
	echo "<tr>";
	echo "<th>ID</th><th>Task Title</th>";
	echo "</tr>";
	echo "<tr>";
	echo "<td>" . $value->tid . "</td><td>" . $value->tname . "</td><td>";
	echo "</tr>";
	echo "</table>";
	echo "</div>";
}

As a conclusion, I would suggest usage of Eloquent as you primary option, but in case that for some reason, that is not an option for you, this approach can do the trick.

PHP console log – The easiest way

PHP console log – The easiest way is to use JavaScript inside PHP, and that can be done with the simple trick.


$str = "Cars";
$arr = array("Volvo", "BMW", "Saab");

echo("<script>console.log('Log: ".$str."');</script>");
echo "<br>";
echo("<script>console.log('Log: ".json_encode($arr)."');</script>");

You will probably notice the difference between 2 logs. One have json_encode, another doesn’t. There is no need to use it when we want to log a string, but when we want to log an array, we need it, because otherwise it will just log information that you dealing with array(s), without values.

Example with json_encode.

PHP console log

Without json_encode.

PHP console log

MySQL Union with Order By

When you execute commands that contains UNION and ORDER BY in MySQL like this one:


(SELECT col1 FROM tab1 WHERE ... ORDER BY col1 ASC) 
UNION
(SELECT col1 FROM tab2 WHERE ... ORDER BY col1 ASC);

you expect to get col1 from tab1 (ordered ascending by col1) “joined” with col1 from tab2 (ordered ascending by col1).

And in some cases you will get the desired rusult, but in some situations query execution will ignore ORDER BY in both SELECT statements.

I think that depends on version of mysql server, which is used. In my case it doesn’t work on Linux Server – MariaDB 10.0.25, but it works on MAMP’s MySQL – 5.6.35.

Anyway, the only way to make sure that ORDER BY will work for all SELECT’s in UNION, is simply to add LIMIT.

So, the example from above should look like this:


(SELECT col1 FROM tab1 WHERE ... ORDER BY col1 ASC LIMIT 10) 
UNION
(SELECT col1 FROM tab2 WHERE ... ORDER BY col1 ASC LIMIT 10);

This is the official explanation from dev.mysql.com

“Use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result because UNION by default produces an unordered set of rows. Therefore, the use of ORDER BY in this context is typically in conjunction with LIMIT, so that it is used to determine the subset of the selected rows to retrieve for the SELECT, even though it does not necessarily affect the order of those rows in the final UNION result. If ORDER BY appears without LIMIT in a SELECT, it is optimized away because it will have no effect anyway.”

Hope that this article helped with this, at least for me, unusual problem.

Magento 2 – Cookies with JavaScript

This article is basically follow up on previous one.

There I talked about popup/sliding panel handling, but if you want to improve that with cookies usage (for example, to auto-load popup just once per session or similar …) here you can find some useful tips.

In Magento 2 you can achieve that with PHP or JavaScript (jQuery, mage/cookies, js-cookie, …)

From what I have experienced, the best way is with the js-cookie plugin (inheritor of jQuery Cookies which is “retired” from 2015).

Why not PHP?
PHP approach cannot be implemented in custom block from Magento backend, and JavaScript can through require.js.

Why not jQuery Cookies plugin?
As I mentioned, it’s retired from 2015, and people who worked on it continued the job on js-cookie plugin. Beside that, cookie retrieving not working anymore (at least for me).

So which one?
That plugin can be found here – https://github.com/js-cookie/js-cookie

Only file that you need is – https://github.com/js-cookie/js-cookie/blob/master/src/js.cookie.js

So, steps for the implementation are:

1. Place js.cookie.js in \lib\web
2. Run Static Content Deploy command – php bin/magento setup:static-content:deploy
3. Go to place where you want to use js-cookie and call it.

    require(
        [
            'jquery',
            'js.cookie'
        ],
        function($, Cookies) { …. }

Usage:
Set cookie – Cookies.set(‘name’, ‘value’, { expires: 30 }); // expires in 30 days
Get cookie – Cookies.get(‘name’); //returns value
Remove cookie – Cookies.remove(‘name’);

Complete documentation can be found here
https://github.com/js-cookie/js-cookie

Updated code from the previous article now looks:

<script type="text/javascript">
    require(
        [
            'jquery',
            'Magento_Ui/js/modal/modal',
            'js.cookie'
        ],
        function($, modal, Cookie){
            var options = {
                type: 'popup', // there is also a slide type. By default sliding from the right.
                responsive: true,
                innerScroll: true,
                buttons: [{
                    text: $.mage.__('Close'),
                    class: '',
                    click: function () {
                        this.closeModal();
                    }
                }]
            };
 
            var popup = modal(options, $('#popup-modal'));
             
            //Popup appears on winodow load only once in session
            $( document ).ready(function() {
                    var cookieGet = Cookies.getJSON('amishown');
                    if (cookieGet === null || cookieGet === undefined){
                    $("#popup-modal").modal("openModal");
	            var cookieSet = Cookies.set('amishown', 'shown');
                    } 
             });
        }
    );
</script>

Magento 2 – Popup/slide modal handling

Magento 2 offers very easy way to use popup or sliding panels.

It can be achieved with the following piece of jQuery code anywhere you want (blocks, pages, templates, …).

<script type="text/javascript">
	require(
		[
			'jquery',
			'Magento_Ui/js/modal/modal'
		],
		function($, modal){
			var options = {
				type: 'popup', // there is also a slide type. By default sliding from the right.
				responsive: true,
				innerScroll: true,
				buttons: [{
					text: $.mage.__('Close'),
					class: '',
					click: function () {
						this.closeModal();
					}
				}]
			};

			var popup = modal(options, $('#popup-modal'));
			
			//Popup appears on click on specific emelent with id=click-me			
			$("#click-me").on('click',function(){ 
				$("#popup-modal").modal("openModal");
			});
			
			//Popup appears on winodow load
			$('#popup-modal').modal('openModal');
		}
	);
</script>

Also, you will need some html.

<!-- Link which will trigger popup on click. -->
<a href="#" id="click-me">Click me</a>

<!-- Popup content. -->
<div id="popup-modal">Here goes content modal</div>

As you can it is very easy to handle events (click, on window load, hover, …).

There are 2 types of modals in magento – Popup and Sliding Panel.

More about modal options you can find in official Magento documentation.