Contextual binding in laravel and how to make your code meet O in SOLID principles

Sometimes, we meet these kind of use cases or features when doing web application programming:

1 – multiple type of report to generate

2-  multiple type of discount to handle

3- multiple type of payment to handle

I recently faced with this use case when doing a freelance project for my customer.

The requirement for this use case is that we have 2 types of reporting: human resources reporting and accounting reporting. And, for quick and dirty we have simple solution for this as below (we use laravel framework 5)

In routes.php, I added this line

type can be: hr or accounting

and the ReportController controller file, in this file based on type of $type variable, we will call the correspond function.

and we simple have the ReportRepository

now, try php artsian serve, and go to localhost:

http://localhost:8000/report/hr or http://localhost:8000/report/accounting

accounting report
accounting report
hr-report-eg
hr-report-eg

The idea for this simple solution is that:

  • In ReportController.php, I injected ReportRepository class into
  • For each type of report (report/accounting or report/hr), the instance $report (type of ReportRepository) will call correspond function with the type of report.

The problem with this way is that it violated Open for extension and close for modification (O) rule in SOLID principle ( I have an article about SOLID principle here ) . For e.g: In case, you have another type of report, you must go to the controller and add more if condition, and add more code for the new report type in ReportRepository as well.

By following the O in SOLID principle, you can reduce if condition, separating the of concern of type of report into another class (in this case, I used laravel fw – so the class file is ApplicationServiceProvider), decoupling code dependency and easy for testing (mocking the interface is alway easy).

So, let’s implement new way that follow O in SOLID principle.

The idea for this way is:

  • For each type of report, there will be an implementation of function show of ReportRepositoryInteface interface.
  • Injecting ReportRepositoryInteface into each controller for each type of report
  • Binding based context ( type of report) in AppServiceProvider class

I hope it much easier for you to understand the second implementation with this diagram ( not actually class diagram)

class diagram for example use case
class diagram for example use case

First, we need ReportRepositoryInterface.php file

then, AccountingReportRepository.php

and HrReportRepository.php

Then, how to make those code work in laravel framework, yah, laravel >5 support contextual binding here https://laravel.com/docs/5.1/container#contextual-binding

adding 2 lines into the routes.php file

It is more reasonable to consider report is an action in AccountingController or HrController ?? 🙂

AccountingController.php

HrController.php

Then, you just need to bind the concrete class to abstract class just in contextual. The logic is as it is:

  • when AccountingController need ReportRepositoryInterface give it AccountReportRepository
  • when HrController need ReportRepositoryInterface give it HrReportRepository

and, just need to add the code in register function of AppServiceProvider (github code)

github code for this tutorial (it may contain code of another tutorial):

https://github.com/nguyentienlong/laravel_sandbox_validation/tree/context-binding/

reference:

https://laracasts.com/discuss/channels/general-discussion/what-do-you-think-about-contextual-binding-ioc-laravel-5

@todo: write a demo test code for the repository

Join with multiple condition in eloquent

Sometimes, you want to use join or left join or right join, etc … in eloquent, here is one example

This will be same as raw sql query (postgres):

Hope this will save  your time

 

Một vài lưu ý khi cài đặt php7 (php-fpm) từ source code trên linux (fedora)

Giả sử bạn muốn cài đặt trên fedora, php7, php-fpm với nginx là proxy hứng request đẩy qua cho php xử lý (thông qua php-fpm).

Khi cài đặt từ source code có thể bạn sẽ gặp những vấn đề sau:

  1. Thiếu các thư viện khi chạy lệnh ./congigure
  2. Chỉ định đường dẫn đến thư mục sẽ cài php mà bạn muốn( hữu ích khi bạn muốn cài nhiều phiên bản php trên môi trường làm việc của bạn).
  3. Chỉ định đường dẫn đến file php.ini
  • Thiếu các thư viện khi chạy lệnh ./congigure

Tuỳ theo các tuỳ chọn của bạn, khi chạy lệnh ./configure bạn có thể thiếu những thư viện mà php cần, ví dụ bạn thiếu thư viện liên quan đến utf8 chẳng hạn, hãy dùng yum để tìm

  • Chỉ định đường dẫn đến file php.ini

Khi đó bạn chỉ cần copy file php.ini vào thư mục /etc/php7/php.ini, mọi thay đổi trong file này, sẽ ảnh hưởng đến cấu hình của php trên máy của bạn.

  • Chỉ định đường dẫn sẽ cài php ( hữu ích khi bạn muốn cài nhiều phiên bản php trên môi trường làm việc của bạn).

Lưu ý nữa: khi bạn khởi động php-fpm, mặc định php-fpm sẽ đọc file cấu hình của php-fpm tại /usr/local/etc/php-fpm.conf. Nếu bạn muốn chỉ định đến file cấu hình php-fpm trong thư mục cài đặt php /opt/php7/etc/php-fpm.conf.

 

Đây là script mình lưu trên gíst
https://gist.github.com/nguyentienlong/120af89ab11e5ec48014

Tham khảo:
http://php.net/manual/en/install.pecl.php-config.php
http://php.net/manual/en/install.unix.nginx.php

Release optivo mail client for laravel

Optivo is quite big mail service provider in Germany https://www.optivo.com/en.
This is one of optivo mail client for laravel (use Optivo HTTP API)
https://github.com/nguyentienlong/laravel-optivo
https://packagist.org/packages/longka/laravel-optivo

Todo:
write an article about how to create your own laravel package like this package

Vọc vạch View trong laravel

Bài này dịch từ bài này 😉

Khi làm việc với laravel, chắc hẳn bạn dùng rất nhiều đoạn code này. Nó rất tiện lợi trong việc trả về một view sau khi controller thực thi các tác vụ liên quan đến business requirement.

Tuy nhiên, nó làm việc thế nào, hơi bị ảo đúng không nhỉ? Cùng đào sâu tìm hiểu thử xem thế nào? 🙂

Đây là tài liệu từ laravel về views: https://laravel.com/docs/master/views

Nhưng mình nghĩ nó không đầy đủ lắm, đào sâu xem coi thử nó chạy sao nhỉ?

Đầu tiên, laravel có hàm view được viết trong file helpers.php. Đây là file helpers

Illuminate\Foundation\helpers.php

Mình nghĩ ,có 2 thứ cần xem xét ở đây

1. $factory = app(ViewFactory::class);

2. return $factory->make($view, $data, $mergeData);

Đầu tiên (tiền đâu) là $factory = app(ViewFactory::class);

Thực ra, nó tạo ra một thực thể $factory (và được inject vào thực thể $app). Khi ứng dụng được khởi tạo thì nó sẽ gọi hàm registerCoreContainerAliases (github code).

Cùng xem thử hàm registerCoreContainerAliases xem sao nhé

Để ý rằng view là alias, bạn có thể đặt bất kỳ cái tên nào khác tùy ý (vd: myView, viewCuaTao, etc …)

Sau đó trong file Illuminate\View\ViewServiceProvider.php, xem thử hàm registerFactory

Như đã đề cập ở trên, tên view này có thể là bất kỳ thứ quái gì, miễn là bạn đặt cùng tên trong 3 files (helpers.php, Application.php,ViewServiceProvider.php)

Thứ 2: return $factory->make($view, $data, $mergeData);

Cùng xem thử hàm make xem sao nào?

Nó sẽ trả về đối tượng View (\Illuminate\View\View)

Đơn giản thế thôi (nếu không hiểu thì còm liền :v )

Nếu bạn có thắc mắc gì, vui lòng còm bên dưới.

Deeper look into laravel view helper function

When working with laravel, you may use this line of code pretty much. Its really helpfull to return a view after calling those business stuff inside a controller.

However, have you ever ask yourself that how does it work ?

Well, you can check with Laravel document about view here

https://laravel.com/docs/master/views

But, I think it’s not adequate. How that line of code actually works ?

Well, let’s try to dig into it

First of all, helpers function view, where is it defined? Here is it

Illuminate\Foundation\helpers.php

Well, IMO, two things need to consider:

1. $factory = app(ViewFactory::class);

2. return $factory->make($view, $data, $mergeData);

First: take a look at $factory = app(ViewFactory::class);

well, it created a $factory instance ( inject into $app instance as well). When the application is instantiated, it calls registerCoreContainerAliases  (github code).

Let’s take a look into registerCoreContainerAliases function (github code).

Remember that view is alias, you can tweak with other name such as myView (for eg)

Then in the file Illuminate\View\ViewServiceProvider.php, the function registerFactory

The name of the view can be whatever (for eg: fooView, barView, blahblahView … etc), just to make sure that you use the same name through those 3 files (helpers.php, Application.php, ViewServiceProvider.php)

Then: return $factory->make($view, $data, $mergeData);

Then $factory calls make function

Its will return a View (\Illuminate\View\View) instance

That’s it 😉

Please leave a comments if you found any mistake or inappropriate point 😉

This post to Vietnamese 😉 http://longka.info/blog/2016/02/02/voc-vach-view-trong-laravel/

Laravel 5 BindingResolutionException in Container.php line 827

Error:

laravel-ioc-binding-exception
laravel-ioc-binding-exception

Context that caused this eror

test controller
test controller
foo service with php primitive type
foo service with php primitive type

When working with laravel 5, have you ever ask yourself that how Laravel IOC work, how Laravel IOC can handle concrete class binding instead of defining in somewhere (for laravel in Service providers).

Basically, if you inject a concrete class to another class, it will automatically bind to that class by laravel Container

Overview of Laravel Container (make, build, getDependencies, resolveClass (or nonClass))

Screenshot from 2016-03-14 09:38:57

 

 

 

 

 

laravel 5 container class:
make function
build function
getDependencies function

By default, If you inject a concrete class to another class, its will automatically bind and resolve by Laravel container.

Service Container Laravel The PHP Framework For Web Artisans
Service Container Laravel The PHP Framework For Web Artisans
laravel ioc build class based on concrete class name
laravel ioc build class based on concrete class name

but, in case in the constructor of some class you inject to a string or non-class parameter, how laravel 5 handle this  https://github.com/laravel/framework/blob/5.2/src/Illuminate/Container/Container.php#L793

laravle-container-getDependencies
laravle-container-getDependencies

Its not acceptable that throw an error if a non-class cannot resolveable, but its not make sense to make a function name resolveNonClass just only throw an error (imo, should handle this 😉

There is many ways to deal with this is that writing an service provider to inject a string to another class like this (basically, a service provider abstract class contains $app instance, just bind a dependency manually into it). This is one way

then register above service provider to config/app.php
 

its works!!!, other way to bypass this, is use Str provider class instead of built in string primitive php type.

foo service with Str class
foo service with Str class

By the way, need to update Laravel Container class to deal with primitive type ??? in this function resolveNonClass https://github.com/laravel/framework/blob/5.2/src/Illuminate/Container/Container.php#L823

laravel fw container resolveNonClass
laravel fw container resolveNonClass

Reference:
https://laravel.com/docs/5.1/container
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Container/Container.php
http://culttt.com/2014/03/24/exploring-laravels-ioc-container/
http://php.net/manual/en/class.reflectionclass.php