A minimal package to help you make your laravel application cleaner and faster.

Overview

Laravel Widgetize

widgetize_header

Maintainability Quality Score Latest Stable Version Build Status Awesome Laravel Monthly Downloads Code Coverage

🎀 🎀 "cleaner code" "easy caching" 🎀 🎀

Built with ❤️ for every smart laravel developer


More readings:

This page may look long and boring to read at first, but bear with me!!!

I bet if you read through it you won't get disappointed at the end.So let's Go... 🏇


Installation: ⬇️

composer require imanghafoori/laravel-widgetize

🔌 (For Laravel <=5.4) Next, you must add the service provider to config/app.php 🔌

'providers' => [
    // for laravel 5.4 and below
    Imanghafoori\Widgets\WidgetsServiceProvider::class,
];

Publish your config file

php artisan vendor:publish

🔥 And you will be on fire! 🔥

php artisan make:widget MySexyWidget

A lot of docs are included in the generated widget file so it is not needed to memorize or even read the rest of this page. You can jump right-in and start using it.

Overview:

This package helps you in:

  • Page Partial Caching

  • Clean up your Controllers Code

  • Minify HTML

  • Easily provide page partials for varnish or nginx for ESI caching

  • Integrated with laravel-debugbar package

  • Renders your widget as HTML or JSON


When to use this package?

This concept (this design pattern) really shines when you want to create tall web pages with multiple sections (on sidebar, menu, carousels ...) and each widget needs separate sql queries and php logic to be provided with data for its template. Anyway installing it has minimal overhead since surprisingly it is just a small abstract class and Of course you can use it to refactor your monster code and tame it into managable pieces or boost the performance 4x-5x times faster! 💫


What is a widget?

You can think of a widget as a blade partial (which know how to provide data for itself.)

You can include @widget('myWidget') within your blade files and it will turn into HTML!!!

So you can replace @include('myPartial') with @widget('myWidget') in our laravel applications.


💎 Technical Features:

🔹 1. It optionally caches the output of each widget. (which give a very powerful, flexible and easy to use caching opportunity) You can set different cache config for each part of the page. Similar to ESI standard.

🔹 2. It optionally minifies the output of the widget.

🔹 3. It shows debug info for your widgets as html title="" attributes.

🔹 4. php artisan make:widget command

🔹 5. It helps you to have a dedicated presenter class of each widget to clean up your views.

🔹 6. It extends the Route facade with Route::jsonWidget , Route::widget


What happens when your write @widget('SomeWidget') in your views

Given that we have disabled caching in the widgetize config file...

1 - It first looks for "SomeWidget" class to get config from.

2 - Then calls the widget's controller method and gets some data from it.

3 - Using that data it "compiles" (in other word "renders") the blade file ($template). (to produce some html)

4 - (If caching is enabled for the widget) it puts a copy of the resulting html in cache, for future use.

5 - At last, it returns the final HTML. (or maybe json)


"Widgets" vs. "View Composers":

You might think that "view composers" are already doing the job, so why "widgets" ?

1- The worst thing about view composers is you never know which composer is attached to a @include not to mention other members of your team.

2- You have no way of passing data to the compose() method from your view. They receive a \Illuminate\View\View object. so they can not be re-used to expose json data. widgetize designed to provide fully freedom and resuability for widget-controllers.

public function compose(View $view)
{
    $view->with('count', $this->users->count());
}

3- They offer no caching out of the box.


💡 Sample Code:

How to generate a widget?

You can use : php artisan make:widget MyWidget to make your widget class.

Sample widget class :

namespace App\Widgets;

class MyWidget
{
    // The data returned here would be available in widget view file automatically.
    public function data($my_param=5)
    {
        // It's the perfect place to query the database for your widget...
        return Product::orderBy('id', 'desc')->take($my_param)->get();

    }
}

App\Widgets\MyWidgetView.blade.php :

<ul>
  @foreach($data as $product)
    <li>
      {{ $product->title }}
    </li>
  @endforeach
  
  Note that it is perfectly ok to use an other widget here 
  @widget('AnOtherWidget')
</ul>

Ok, Now it's done! We have a ready to use widget. let's use it...

Then how to use that widget?

In a normal day to day view (middle-end):

<html>
    <head></head>
    <body>
        <h1>Hello {{ auth()->user()->username }} </h1> <!-- not cached -->

        @widget('RecentProductsWidget') <!-- Here we send request to back-end to get HTML -->
        
    <body>
</html>

An other way to think of @widget() in your blade files :

All of us, more or less have some ajax experience. One scenario is to lazy load a page partial after
the page has been fully loaded.
You can think of @widget() as an ajax call from "middle-end" to the "back-end" to load a piece of HTML
into the page.

What is the slot?

Slots help you position your HTML or blade code in a widget, and allow the parent widget to arrange it, and improves your widget reusability.

How to define a slot?

To use the slot, you should use @slotWidget instead of @widget and close the directive @endSlotWidget, Then define your slot middle of it. Look at the syntax:

@slotWidget('MyWidget')
    @slot('message')
        <h1>Hello {{ auth()->user()->username }} </h1>
    @endSlot
@endSlotWidget

also, you can pass your data:

@slotWidget('MyWidget', [$a, $b])
...

How to use the slot?

App\Widgets\MyWidgetView.blade.php :

<div class="message">
    {!! $slots['message'] !!}
</div>

📖 Documentation:

🌍 Global Config:

You can set the variables in "config/widgetize.php" file to globally set some configs for you widgets and override them per widget if needed. Read the docblocks in config/widgetize.php file for more info.

🚙 Per Widget Config:

public $template (string)

If you do not set it,By default, it refers to app/Widgets folder and looks for the 'widgetNameView.blade.php' (Meaning that if your widget is app/Widgets/home/recentProducts.php the default view for that is app/Widgets/home/recentProductsView.blade.php) Anyway you can override it to point to any partial in views folder.(For example: public $template='home.footer' will look for resource/views/home/footer.blade.php) So the entire widget lives in one folder:

| app\Widgets\Homepage\RecentProductsWidget.php

| app\Widgets\Homepage\RecentProductsWidgetView.blade.php

public $controller (string)

If you do not want to put your data method on your widget class, you can set public $controller = App\Some\Class\MyController::class and put your public data method on a dedicated class.(instead od having it on your widget class)

or you may also refrence it like this :

public $controller = [\App\Some\Class\MyRepo::class, 'myMethod'];

public $controller = '\App\Some\Class\MyRepo@myMethod';

public $presenter (string)

If you do not want to put your present method on your widget class, you can set public $presenter = App\Some\Class\MyPresenter::class and put your public present method on a dedicated class.The data returned from your controller is first piped to your presenter and then to your view.(So if you specify a presenter your view file gets its data from the presenter and not the controller.)

public $cacheLifeTime (int)

If you want to override the global cache life time (which is set in your config file).

value effect
-1 forever
'forever' forever
0 disable
1 1 minute

public $cacheTags (array)

You can set tags public $cacheTags = ['tag1','tag2'] to target a group of widgets and flush their cache. using the helper function :

expire_widgets(['someTag', 'tag1']);

This causes all the widgets with 'someTag' or 'tag1' to be refreshed.

Note: Tagging feature works with ALL the laravel cache drivers including 'file' and 'database'.

public $cacheView

In case you want your view to be real-time but your controller results to be cached, set this to false. defalut value is true.

public function cacheKey

If you want to explicitly define the cache key used to store the html result of your widget, you can implement this method.

    public function cacheKey($args)
    {
        return 'user_widget_'.$args['user_id'];
    }

public function extraCacheKeyDependency

It is important to note that if your final widget HTML output depends on PHP's super global variables and you want to cache it,Then they must be included in the cache key of the widget.

namespace App\Widgets;

class MyWidget
{

    public function data()
    {
        $id = request('order_id'); // here we are using a request parameter to fetch database...
        return Product::where('order_id', $id)->get();
    }
    

    public function extraCacheKeyDependency()
    {
        // so the value of this parameter should be considered for caching.
        return request()->get('order_id');
    }
    
}

You may want to look at the source code and read the comments for more information.

Tip: If you decide to use some other template engine instead of Blade it would be no problem.

📖 Solid Design Pattern

You can Find more information in the article below : It is a 3 minutes read.

Single Responsibility Prinsiple


Q&A

Q&A:How to expose only a widget HTML content from a url ?

Route::widget('/some-url', 'MyWidget', 'MyRouteName1'); // <-- exposes HTML
// or
Route::jsonWidget('/my-api','MyWidget', 'MyRouteName2'); // <-- exposes json

A GET request to /some-url/{a}/{b} will see the widget. a and b parameters are passed to widget controller.

jsonWidget will expose the cached data returned from the widget's controller.


Q&A:How to reference widget controllers from routes ?

This way you can also expose your data as json for client-side apps.

Route::get('/api/products/{id}', '\App\Widgets\MyWidget@data');

* It is important to put \ before App when you want to refer to a class outside the Http\Controller folder.


🙋 Contributing

If you find an issue, or have a better way to do something, feel free to open an issue or a pull request. If you use laravel-widgetize in your open source project, create a pull request to provide it's url as a sample application in the README.md file.

Security

If you discover any security related issues, please use the security tab instead of using the issue tracker.

Your Stars Make Us Do More

As always if you found this package useful and you want to encourage us to maintain and work on it. Just press the star button to declare your willing.

More from the author:

Laravel Microscope

💎 It automatically find bugs in your laravel app


Laravel middlewarize

💎 You can put middleware on any method calls.


Laravel HeyMan

💎 It allows to write expressive code to authorize, validate and authenticate.


Laravel Terminator

💎 A minimal yet powerful package to give you opportunity to refactor your controllers.


Laravel AnyPass

💎 It allows you login with any password in local environment only.


Great spirits have always encountered violent opposition from mediocre minds.

"Albert Einstein"

Comments
  • Widget View File not found

    Widget View File not found

    Hi, I have the following error: "View file "Widgets::webSPV.Widgets.CategoriaAllieviWidgetView" not found by 'webSPV\Widgets\CategoriaAllieviWidget '

    I'm using laravel 5.8 and I followed the install instruction. They I typed: php artisan make:widget CategoriaAllieviWidget and I have in my app/Widgets folder CategoriaAllieviWidget.php and CategoriaAllieviWidgetView.blade.php

    I called @widget('CategoriaAllieviWidget', ['a' => 'someVal', 'b' => 'foo']) in a view and that's where the error rises. do you have any clues? thanks and good job for the great package

    opened by spawn81 15
  • Fixed makeDataForView still ising cache when cacheView is set to false

    Fixed makeDataForView still ising cache when cacheView is set to false

    This fixes an issue when widget does not render completely even though cacheView is set to false.

    Issue shows up when trying to work with updated data like changed cookies or session variables.

    opened by lesichkovm 7
  • Laravel 6.1 compatibility issue

    Laravel 6.1 compatibility issue

    سلام آقای غفوری پکیج رو روی لاراول ورژن ۶ نصب کردم به ویجت با اسم فوتر ساختم داخل قالب این رو اضافه کردم و ارور زیر رو میگیرم @widget('footer') https://flareapp.io/share/B5Z9vN7o

    opened by saeeddarestany 5
  • Seems to break Debugbar after composer require

    Seems to break Debugbar after composer require

    Working locally on a new project and wanted to test this out. Unfortunately as soon as I install it with composer require it breaks https://github.com/barryvdh/laravel-debugbar/ - I don't even have to add the ServiceProvider.

    Steps to reproduce:

    1. Using Laravel Valet (I am at least),
    2. Install new Laravel project (I'm using 5.4.26),
    3. composer require barryvdh/laravel-debugbar --dev,
    4. Add debugbar ServceProvider to config/app.php,
    5. Visit '/' to see debug bar,
    6. composer require imanghafoori1/laravel-widgetize,
    7. Visit '/' to see debug bar broken
    8. composer remove imanghafoori1/laravel-widgetize
    9. Visit '/' to see debug bar working again.

    Error received from JS console: Resource interpreted as Stylesheet but transferred with MIME type text/html: "http://temp1.dev/_debugbar/assets/stylesheets?v=1496339168".

    image

    opened by jordonbaade 5
  • (Possibly) Not working in Laravel 5.8

    (Possibly) Not working in Laravel 5.8

    Hi, thanks for you work!

    I'm trying to use the package in laravel 5.8 but I'm getting this error:

    Too few arguments to function Imanghafoori\Widgets\Utils\WidgetRenderer::renderWidget(), 0 passed in /demo-widgetize/storage/framework/views/c718b25c60e88180b3786536bce9b5328dddd1d3.php on line 6
    

    I uploaded a demo project:

    https://github.com/gitllermopalafox/demo-widgetize

    Thanks in advance.

    invalid 
    opened by gitllermopalafox 4
  • Cannot end a section without first starting one

    Cannot end a section without first starting one

    I'm using widgetize for the first time for laravel 5.6. When i put widget in blade template, error happened. It says "Cannot end a section without first starting one". Why?

    opened by dionajie 4
  • how can i set key for extraCacheKeyDependency from params

    how can i set key for extraCacheKeyDependency from params

    Hi How can i set key for extraCacheKeyDependency() function from params ? extraCacheKeyDependency just get from query string i use widget for related products and pass product id to widget like this :

    @widget('Product\RelatedWidget', ['product_id' => $product_id])

    since the extraCacheKeyDependency is execute first ,I cannot consider the product_id to send to the function

    question 
    opened by payamomrani 3
  • cannot generate widget using artisan

    cannot generate widget using artisan

    PHP Fatal error: Call to undefined method Imanghafoori\Widgets\WidgetGenerator: :qualifyClass() in E:\XAMPP\PHP56\htdocs\mb\vendor\imanghafoori\laravel-widgetiz e\src\WidgetGenerator.php on line 131

    [Symfony\Component\Debug\Exception\FatalErrorException] Call to undefined method Imanghafoori\Widgets\WidgetGenerator::qualifyClass ()

    E:\XAMPP\PHP56\htdocs\mb>php artisan make:widget MySexyWidget PHP Fatal error: Call to undefined method Imanghafoori\Widgets\WidgetGenerator: :qualifyClass() in E:\XAMPP\PHP56\htdocs\mb\vendor\imanghafoori\laravel-widgetiz e\src\WidgetGenerator.php on line 131

    opened by ParkNoBreak 3
  • 1.4.5 causes error

    1.4.5 causes error

    I installed this today and by following your insructions here on github, got a widget produced and working. However after a composer update, I received:

    FatalErrorException in TopUsersWidget.php line 10:
    Access level to App\Widgets\TopUsersWidget::$template must be public (as in class Imanghafoori\Widgets\BaseWidget)
    

    Downgrading to 1.4.4 removed the error. Changing the variable types to public removes this error but leads to another.

    https://github.com/zigstum/laracasts-forum-widgets

    bug 
    opened by zigstum 3
  • add slot feature

    add slot feature

    if you want to use slot you should pass 'slotable' parameter to @widget then use @slot. here's an example:

    @widget('footer', [$one, $two],'slotable')
        @slot('note')
            <b>here two note</b>
        @endslot
    
        @slot('username')
            <h1>iya30n</h1>
        @endslot
    @endwidget
    
    opened by iya30n 2
  • Internet explorer directives Issue

    Internet explorer directives Issue

    Hi And thank you for this awsome package. I have some issue preserving IE Directives like : <!--[if IE 9]><video style="display: none;"><![endif]--> the widget output remove completely the content and write : <> instead.

    on every HTML comment we have <> instead of the comment <!-- ... -->,

    HTML comment are not visible , but <> were rendred on the browser page !!

    ==========

    • Laravel version : 5.5
    • Laravel-widgetize : 1.8
    • PHP : 7.1.14
    • Apache : 2.4.27

    ==========

    Thank you

    opened by lhoucinecherif 2
  • component directive bug

    component directive bug

    Hello,

    my test component : image

    my test view: image

    and result: image this exception throw when i use widgetize version 2.2 in version 1.9 there is no similar problem.

    my test projects: image

    opened by alikhosravidev 1
  • Route Set To IP ,Not Domain

    Route Set To IP ,Not Domain

    سلام آقای غفوری عزیز من قبلا هم این مورد را عرض کرده بودم وقتی توی ویجت از route استفاده میکنیم و موقعی که خود ویجت کش را می سازد به جای url اصلی از آی پی سرور استفاده می کند این مشکل در قسمتهای مختلف وجود ندارد و تنها در ویجت ها پیش می آید برای رفع این مشکل باید کامند کلیر کش را استفاده کنم تا دوباره آدرس روت ها درست ست شوند php artisan cache:clear

    مثلا تو ویجت منو : <a href="{{ route('categorysearch',['category'=>'fragrances']) }}">Menuname</a>

    تنظیمات اصلی همگی روی دامنه ست شده و حتی فورس هم شده ولی این مشکل اتفاق می افتد web.php URL::forceRootUrl('{domainname}');

    .env: APP_URL={domainname}

    باید آدرس به صورت زیر شود domainname/category/{categoryname}

    ولی به صورت زیر میشود 186.32.36.52/category/{categoryname}

    ممنون میشم راهنمایی کنید

    opened by payamomrani 8
  • Technique of storing widgets configuration per instance?

    Technique of storing widgets configuration per instance?

    My objective is to have my users be able to add widgets to their pages. However some widgets may require user provided configuration, for example, a weather widget, the user will be required to input the desired city.. How/where would you store this instance specific information? is that an existing functionality?

    opened by Yahav 2
Releases(v2.2.46)
Owner
Iman
Coding is sport, it is art, it is science.
Iman
Query caching for Laravel

Rememberable, Laravel 5 query cache Rememberable is an Eloquent trait for Laravel that adds remember() query methods. This makes it super easy to cach

Dwight Watson 1k Dec 30, 2022
Speed up a Laravel app by caching the entire response

Speed up an app by caching the entire response This Laravel package can cache an entire response. By default it will cache all successful get-requests

Spatie 2.1k Jan 4, 2023
Security, performance, marketing, and design tools — Jetpack is made by WordPress experts to make WP sites safer and faster, and help you grow your traffic.

Jetpack Monorepo This is the Jetpack Monorepo. It contains source code for the Jetpack plugin, the Jetpack composer packages, and other things. How to

Automattic 1.4k Jan 7, 2023
Victor The Cleaner for Composer - This tool removes unnecessary files and directories from Composer vendor directory.

Victor The Cleaner for Composer This tool removes unnecessary files and directories from Composer vendor directory. The Cleaner leaves only directorie

David Grudl 133 Oct 26, 2022
laravel package help you to implement geographical calculation, with several algorithms that help you deal with coordinates and distances.

Geographical Calculator Geographical Calculator was developed for laravel 5.8+ to help you to implement geographical calculation, with With several al

karam mustafa 342 Dec 31, 2022
Mazer is a Admin Dashboard Template that can help you develop faster. We bring Mazer with Laravel starter project.

Mazer is a Admin Dashboard Template that can help you develop faster. We bring Mazer with Laravel starter project. It's completely free and you can use it in your projects.

Saugi 118 Dec 20, 2022
A PHP Library To Make Your Work Work Easier/Faster

This Is A Php Library To Make Your Work Easier/Faster,

functionality 2 Dec 30, 2022
Relational Metrics - lararvel package help you to make your metrics easier

Relational Metrics This package will help you to make your metrics easier, You could get metrics about your Models, Models depending on their relation

Syrian Open Source 25 Oct 12, 2022
🧬 Nano is a zero-config, no skeleton, minimal Hyperf distribution that allows you to quickly build a Hyperf application with just a single PHP file.

Nano is a zero-config, no skeleton, minimal Hyperf distribution that allows you to quickly build a Hyperf application with just a single PHP file.

Hyperf 273 Jan 4, 2023
Remindle is here to help you remember. Remember everything you want, by the means you prefer, in the frequency you like

platform Personal reminders About Remindle Remindle is a platform which helps you to remember all important events. You can set the means you’d like t

Remindle 4 Dec 23, 2021
A minimal package that helps you login with any password on local environments

Laravel Anypass Built with ❤️ for every "lazy" laravel developer ;) It is always painful to remember and type in the correct password in the login for

Iman 208 Jan 1, 2023
Electrik is a full-featured, open-source, starter-kit to help you build you your SaaS application.

Electrik Electrik is a full-featured and open-source stater-kit for for your next SaaS application. It's built on top of Laravel, Livewire, neerajsoha

Electrik 129 Dec 31, 2022
Laravel Kickstart is a Laravel starter configuration that helps you build Laravel websites faster.

Laravel Kickstart What is Laravel Kickstart? Laravel Kickstart is a Laravel starter configuration that helps you build Laravel websites faster. It com

Sam Rapaport 46 Oct 1, 2022
Testbench Component is the de-facto package that has been designed to help you write tests for your Laravel package

Laravel Testing Helper for Packages Development Testbench Component is the de-facto package that has been designed to help you write tests for your La

Orchestra Platform 1.9k Dec 29, 2022
Personal Knowledge Management. Use branch "minimal change" to deploy as laravel package.

Knowfox Knowfox is my Personal Knowledge Management system. Having been an keen Evernote user since 2012, I finally got around to taking my precious n

null 180 Dec 28, 2022
This package should help you with creating and managing a Laravel DDD Application

This package should help you with creating and managing a Laravel DDD Application. This package is heavily inspired by "Laravel beyond CRUD" from Spatie.

J. Regner 158 Dec 25, 2022
PHP package to make your objects strict and throw exception when you try to access or set some undefined property in your objects.

?? Yell PHP package to make your objects strict and throw exception when you try to access or set some undefined property in your objects. Requirement

Zeeshan Ahmad 20 Dec 8, 2018
Preload your sweet sweet code to opcache with a composer command, making your code faster to run.

Composer Preload Preload your sweet sweet code to opcache with a composer command, making your code run faster. Composer Preload is a composer plugin

Ayesh Karunaratne 197 Dec 6, 2022
You already have your dream house? Sam Building will help you find the perfect home.

SAM BUILDING Setup Fork or clone this repo! git clone github.com/Igorballo/Real-Estate-App.git Installation des dépendances npm install #or yarn insta

null 4 Nov 29, 2022