laravel-pdf icon indicating copy to clipboard operation
laravel-pdf copied to clipboard

Use contracts instead of facades

Open niklasravnsborg opened this issue 5 years ago • 3 comments

Throughout the project I used Laravel facades: https://github.com/niklasravnsborg/laravel-pdf/blob/913fa50ce9f895a0e08faaf5324cc9aa7826a742/src/LaravelPdf/PdfWrapper.php#L5-L6

It might be better to use contracts instead of facades in order to provide a cleaner abstraction and to be less dependent on the service container: https://laravel.com/docs/5.7/contracts

niklasravnsborg avatar Feb 11 '19 20:02 niklasravnsborg

@niklasravnsborg That is a good idea but there is not that much difference between Facades and Contracts. If you use Contract, the class would need an implementation of that Contract and then, Service Container will inject one to the class. So in this case, we still depend on Service Container, as you know. The only benefit would be more cleanliness which is nice but not necessary.

erfansahaf avatar Feb 11 '19 21:02 erfansahaf

@erfansahaf Right. I just stumbled on this in the Laravel facade documentation:

When building a third-party package that interacts with Laravel, it's better to inject Laravel contracts instead of using facades. Since packages are built outside of Laravel itself, you will not have access to Laravel's facade testing helpers.

https://laravel.com/docs/5.7/facades#when-to-use-facades

Thats why I took a note here :)

niklasravnsborg avatar Feb 12 '19 22:02 niklasravnsborg

Why do you wan't to make it less dependent on the service container? As the service container is most likely staying forever I think it's might be a good idea to use it to it's advantages and implement the wrapper using dependency injection.

It makes sense if you are writing a library for a framework to use the framework features to some extent (eg. Service container).

It would be something like:

<?php

namespace niklasravnsborg\LaravelPdf;

use Illuminate\Filesystem\Filesystem;
use Illuminate\View\Factory;

class PdfWrapper
{

    /**
     * Laravel's blade template renderer
     * @var Factory
     */
    private $viewFactory;

    /**
     * Lavavel file manager
     * @var Filesystem
     */
    private $filesystem;

    public function __construct( Factory $viewFactory, Filesystem $filesystem )
    {
        $this->viewFactory = $viewFactory;
        $this->filesystem = $filesystem;
    }

    /**
     * Load a HTML string
     * @param string $html
     * @return Pdf
     */
    public function loadHTML( $html, $config = [] )
    {
        return new Pdf($html, $config);
    }

    /**
     * Load a HTML file
     * @param string $file
     * @return Pdf
     */
    public function loadFile( $file, $config = [] )
    {
        $html = $this->filesystem->get($file);

        return $this->loadHTML($html, $config);
    }

    /**
     * Load a View and convert to HTML
     * @param string $view
     * @param array $data
     * @param array $mergeData
     * @return Pdf
     */
    public function loadView( $view, $data = [], $mergeData = [], $config = [] )
    {
        $html = $this->viewFactory->make($view, $data, $mergeData)->render();

        return $this->loadHTML($html, $config);
    }

}

And then the binding could be:

$this->app->singleton('mpdf.wrapper', PdfWrapper::class);

Another question would be if that works on older versions of Laravel. I am using PHP 7.4.4 and Laravel 7.X and it works for me. I'm writing this because people with strict PHP Notice/Warnings check and you haven't declared the facades to disallow their usage, you cannot use this library

colorninja avatar Apr 21 '20 19:04 colorninja