{"id":13396265,"url":"https://github.com/imanghafoori1/laravel-widgetize","last_synced_at":"2025-05-14T01:10:51.110Z","repository":{"id":37572708,"uuid":"80939052","full_name":"imanghafoori1/laravel-widgetize","owner":"imanghafoori1","description":"A minimal package to help you make your laravel application cleaner and faster.","archived":false,"fork":false,"pushed_at":"2025-02-23T10:44:04.000Z","size":507,"stargazers_count":906,"open_issues_count":4,"forks_count":73,"subscribers_count":27,"default_branch":"master","last_synced_at":"2025-04-03T07:05:49.717Z","etag":null,"topics":["design-pattern","html-minification","html-minifier","laravel","laravel-5-package","laravel-cache","laravel-optimization","laravel-presenter","laravel-utility","laravel5","presenter"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/imanghafoori1.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-04T18:27:31.000Z","updated_at":"2025-03-13T17:48:53.000Z","dependencies_parsed_at":"2024-01-15T15:46:42.569Z","dependency_job_id":"467993b0-5324-452f-ae73-8d6c5b0d65d6","html_url":"https://github.com/imanghafoori1/laravel-widgetize","commit_stats":{"total_commits":438,"total_committers":10,"mean_commits":43.8,"dds":0.07077625570776258,"last_synced_commit":"06ef31ad0c567954743aac3a584f514f6417cd07"},"previous_names":[],"tags_count":85,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-widgetize","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-widgetize/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-widgetize/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/imanghafoori1%2Flaravel-widgetize/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/imanghafoori1","download_url":"https://codeload.github.com/imanghafoori1/laravel-widgetize/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248224794,"owners_count":21068075,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["design-pattern","html-minification","html-minifier","laravel","laravel-5-package","laravel-cache","laravel-optimization","laravel-presenter","laravel-utility","laravel5","presenter"],"created_at":"2024-07-30T18:00:43.376Z","updated_at":"2025-04-10T13:09:35.790Z","avatar_url":"https://github.com/imanghafoori1.png","language":"PHP","funding_links":[],"categories":["Popular Packages","پی اچ پی PHP","PHP","Paquetes utiles","Packages"],"sub_categories":["Design Pattern Tools"],"readme":"\u003ch1 align=\"center\"\u003e\nLaravel Widgetize\n\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cimg width=\"400px\" src=\"https://cloud.githubusercontent.com/assets/6961695/24345454/7d5c9e4c-12e5-11e7-8c22-015395dbb796.jpg\" alt=\"widgetize_header\"\u003e\u003c/img\u003e\n\u003c/p\u003e\n\n\n\n\n\u003cp align=\"center\"\u003e\n    \n[![Maintainability](https://api.codeclimate.com/v1/badges/265609ba555d5fd06560/maintainability)](https://codeclimate.com/github/imanghafoori1/laravel-widgetize/maintainability)\n\u003ca href=\"https://scrutinizer-ci.com/g/imanghafoori1/laravel-widgetize\"\u003e\u003cimg src=\"https://img.shields.io/scrutinizer/g/imanghafoori1/laravel-widgetize.svg?style=flat-square\" alt=\"Quality Score\"\u003e\u003c/img\u003e\u003c/a\u003e\n[![Latest Stable Version](https://poser.pugx.org/imanghafoori/laravel-widgetize/v/stable)](https://packagist.org/packages/imanghafoori/laravel-widgetize)\n[![Awesome Laravel](https://img.shields.io/badge/Awesome-Laravel-brightgreen.svg)](https://github.com/chiraggude/awesome-laravel)\n[![Monthly Downloads](https://poser.pugx.org/imanghafoori/laravel-widgetize/d/monthly)](https://packagist.org/packages/imanghafoori/laravel-widgetize/stats)\n[![Coverage Status](https://coveralls.io/repos/github/imanghafoori1/laravel-widgetize/badge.svg?branch=master)](https://coveralls.io/github/imanghafoori1/laravel-widgetize?branch=master)\n[![tests](https://github.com/imanghafoori1/laravel-widgetize/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/imanghafoori1/laravel-widgetize/actions/workflows/tests.yml)\n[![Check Imports](https://github.com/imanghafoori1/laravel-widgetize/actions/workflows/imports.yml/badge.svg?branch=master)](https://github.com/imanghafoori1/laravel-widgetize/actions/workflows/imports.yml)\n\u003c/p\u003e\n\n\n\n\u003ch2 align=\"center\"\u003e\n    \n :ribbon::ribbon: \"_cleaner code_\" :heavy_plus_sign: \"_easy caching_\" :ribbon::ribbon:\n\n\u003c/h2\u003e\n\n\u003ch4 align=\"center\"\u003e\nBuilt with :heart: for every smart laravel developer\n\u003c/h4\u003e\n    \n---------------------\n\n\n\n* :flashlight: [Overview](#overview)\n    - [What is a _widget object_ ?](#this-package-helps-you-in)\n    - [When to use the _widget_ concept?](#when-to-use-this-package)\n    - [Technical Features](#gem-technical-features)\n    \n* :wrench: [Installation](#installation-arrow_down)\n* :earth_africa: [Global Configuration](#earth_africa-global-config)\n* :blue_car: [Per Widget Configuration](#blue_car-per-widget-config)\n    - [public $template (optional)](#public-template-string)\n    - [public $cacheLifeTime (optional)](#public-cachelifetime-int)\n    - [public $cacheTags (optional)](#public-cachetags-array)\n    - [public $cacheView (optional)](#public-cacheview)\n    - [public $controller (optional)](#public-controller-string) Advanced\n    - [public $presenter (optional)](#public-presenter-string) Advanced\n    - [public function extraCacheKeyDependency (optional)](#public-function-extracachekeydependency) Advanced\n    - [public function cacheKey (optional)](#public-function-cachekey) Advanced\n   \n   \n* :bulb: [Usage and Example](#bulb-example)\n    - [How to make a widget class](#how-to-make-a-widget)\n    - [How to use a widget class](#how-to-use-a-widget-class)\n    - [What is a slot?](#what's-a-slot-and-how-it-helps-me?)\n    - [How to define a slot](#how-to-define-a-slot)\n    - [How to use the slot](#how-to-use-the-slot)\n   \nMore readings:\n* :shipit: [Some Theory for Experts](#)\n    - [Article about widgetize and S in Solid Design Patterns](https://medium.com/@imanghafoori1/taste-single-responsibility-in-your-laravel-controllers-with-laravel-widgetize-package-9e0800d8b559)\n    - [Article about widgetize and O in Solid Design Patterns](https://medium.com/@imanghafoori1/open-closed-principle-in-laravel-controllers-affc41df2f02)\n\n\n* :star: [Your Stars Makes Us Do More](#star-your-stars-make-us-do-more-star)\n\n\n\n\n\n\nThis page may look long and boring to read at first, but bear with me!!!\n\nI bet if you read through it you won't get disappointed at the end.So let's Go... :horse_racing:\n\n\n-----------------------\n\n\n### Installation: :arrow_down:\n``` bash\ncomposer require imanghafoori/laravel-widgetize\n```\n\n:electric_plug: (For Laravel \u003c=5.4) Next, you must add the service provider to `config/app.php` :electric_plug:\n\n```php\n'providers' =\u003e [\n    // for laravel 5.4 and below\n    Imanghafoori\\Widgets\\WidgetsServiceProvider::class,\n];\n```\n\n__Publish your config file__\n``` bash\nphp artisan vendor:publish\n```\n\n :fire: And you will be on fire!:fire:\n\n``` bash\nphp artisan make:widget MySexyWidget\n```\n\nA 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.\nYou can jump right-in and start using it.\n\n\n## Overview:\n\n### This package helps you in:\n- #### Page Partial Caching\n- #### Clean up your Controllers Code\n- #### Minify HTML\n- #### Easily provide page partials for varnish or nginx for ESI caching\n- #### Integrated with laravel-debugbar package\n- #### Renders your widget as HTML or JSON\n\n---------------\n\n### When to use this package?\n\nThis 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! :dizzy:\n\n-----------------\n\n### What is a widget?\n\nYou can think of a widget as a blade partial (which know how to provide data for itself.)\n\nYou can include `@widget('myWidget')` within your blade files and it will turn into `HTML`!!! \n \n So you can replace `@include('myPartial')` with `@widget('myWidget')` in our laravel applications.\n\n------------------\n\n\n### :gem: Technical Features:\n\n:small_blue_diamond: 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.\n\n:small_blue_diamond: 2. It optionally `minifies` the output of the widget.\n\n:small_blue_diamond: 3. It shows debug info for your widgets as html title=\"\" attributes.\n\n:small_blue_diamond: 4. __php artisan make:widget__ command \n\n:small_blue_diamond: 5. It helps you to have a dedicated presenter class of each widget to clean up your views.\n\n:small_blue_diamond: 6. It extends the Route facade with `Route::jsonWidget` , `Route::widget`\n\n-------------------\n\n#### What happens when your write @widget('SomeWidget') in your views\n\n\nGiven that we have disabled caching in the widgetize config file...\n\n1 - It first looks for \"SomeWidget\" class to get config from.\n\n2 - Then calls the widget's controller method and gets some data from it.\n\n3 - Using that data it \"compiles\" (in other word \"renders\") the blade file ($template). (to produce some html)\n\n4 -  (If caching is enabled for the widget) it puts a copy of the resulting html in cache, for future use.\n\n5 - At last, it returns the final HTML. (or maybe json)\n\n-------------------------\n\n### \"Widgets\" vs. \"View Composers\":\n\nYou might think that \"view composers\" are already doing the job, so why \"widgets\" ?\n\n1- 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.\n\n2- You have no way of passing data to the compose() method from your view.\nThey receive a \\Illuminate\\View\\View object. so they can not be re-used to expose json data.\nwidgetize designed to provide fully freedom and resuability for widget-controllers.\n\n``` php\npublic function compose(View $view)\n{\n    $view-\u003ewith('count', $this-\u003eusers-\u003ecount());\n}\n\n```\n\n3- They offer no caching out of the box.\n\n\n----------------------\n\n\n## :bulb: Sample Code:\n\n\n### How to generate a widget?\n\n\n\u003e__You can use : `php artisan make:widget MyWidget` to make your widget class.__\n\nSample widget class :\n```php\nnamespace App\\Widgets;\n\nclass MyWidget\n{\n    // The data returned here would be available in widget view file automatically.\n    public function data($my_param=5)\n    {\n        // It's the perfect place to query the database for your widget...\n        return Product::orderBy('id', 'desc')-\u003etake($my_param)-\u003eget();\n\n    }\n}\n```\n\n\n\nApp\\Widgets\\MyWidgetView.blade.php :\n\n```blade\n\u003cul\u003e\n  @foreach($data as $product)\n    \u003cli\u003e\n      {{ $product-\u003etitle }}\n    \u003c/li\u003e\n  @endforeach\n  \n  Note that it is perfectly ok to use an other widget here \n  @widget('AnOtherWidget')\n\u003c/ul\u003e\n```\n\nOk, Now it's done! We have a ready to use widget. let's use it...\n\n\n### Then how to use that widget?\n\nIn a normal day to day view (middle-end):\n```blade\n\u003chtml\u003e\n    \u003chead\u003e\u003c/head\u003e\n    \u003cbody\u003e\n        \u003ch1\u003eHello {{ auth()-\u003euser()-\u003eusername }} \u003c/h1\u003e \u003c!-- not cached --\u003e\n\n        @widget('RecentProductsWidget') \u003c!-- Here we send request to back-end to get HTML --\u003e\n        \n    \u003cbody\u003e\n\u003c/html\u003e\n```\n\n---------------------\n\n\n#### __An other way to think of @widget() in your blade files :__\n\n```\nAll of us, more or less have some ajax experience. One scenario is to lazy load a page partial after\nthe page has been fully loaded.\nYou can think of @widget() as an ajax call from \"middle-end\" to the \"back-end\" to load a piece of HTML\ninto the page.\n```\n\n\n\n---------------------\n### What is the slot?\n\nSlots help you position your HTML or blade code in a widget, and allow the parent widget to arrange it, and improves your widget reusability.\n\n### How to define a slot?\n\n\u003e 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:\n\n```blade\n@slotWidget('MyWidget')\n    @slot('message')\n        \u003ch1\u003eHello {{ auth()-\u003euser()-\u003eusername }} \u003c/h1\u003e\n    @endSlot\n@endSlotWidget\n```\n\n\u003e also, you can pass your data:\n\n```blade\n@slotWidget('MyWidget', [$a, $b])\n...\n```\n\n### How to use the slot?\n\nApp\\Widgets\\MyWidgetView.blade.php :\n\n```blade\n\u003cdiv class=\"message\"\u003e\n    {!! $slots['message'] !!}\n\u003c/div\u003e\n```\n\n-----------------\n\n## :book: Documentation:\n\n\n### :earth_africa: Global Config:\n\n\u003e 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.\n\u003eRead the docblocks in __config/widgetize.php__ file for more info. \n\n\n\n### :blue_car: Per Widget Config:\n\n\n#### __public $template__ (string)\n\n\u003eIf you do not set it,By default, it refers to app/Widgets folder and looks for the 'widgetNameView.blade.php'\n(Meaning that if your widget is `app/Widgets/home/recentProducts.php` the default view for that is `app/Widgets/home/recentProductsView.blade.php`)\nAnyway 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)\nSo the entire widget lives in one folder:\n\n\u003e| _app\\Widgets\\Homepage\\RecentProductsWidget.php_\n\n\u003e| _app\\Widgets\\Homepage\\RecentProductsWidgetView.blade.php_\n\n\n#### __public $controller__ (string)\n\n\u003e 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)\n\nor you may also refrence it like this : \n\n`public $controller = [\\App\\Some\\Class\\MyRepo::class, 'myMethod'];`\n\n`public $controller = '\\App\\Some\\Class\\MyRepo@myMethod';`\n\n#### __public $presenter__ (string)\n\n\u003e If you do not want to put your _present_ method on your widget class, you can set\n`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.)\n\n\n\n#### __public $cacheLifeTime__ (int)\n\n\u003e If you want to override the global cache life time (which is set in your config file).\n\n value  | effect\n:-------|:----------\n   -1   | forever\n'forever' | forever\n  0    | disable\n  1    | 1 minute\n\n\n#### __public $cacheTags__ (array)\n\n\u003e You can set tags `public $cacheTags = ['tag1','tag2']` to target a group of widgets and flush their cache.\nusing the helper function :\n\n```php\nexpire_widgets(['someTag', 'tag1']);\n```\nThis causes all the widgets with 'someTag' or 'tag1' to be refreshed.\n\n\n__Note: Tagging feature works with ALL the laravel cache drivers including 'file' and 'database'.__\n\n#### __public $cacheView__\n\n\u003e 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`.\n\n\n#### __public function cacheKey__\n\n\u003e If you want to explicitly define the cache key used to store the html result of your widget, you can implement this method.\n\n```php\n    public function cacheKey($args)\n    {\n        return 'user_widget_'.$args['user_id'];\n    }\n```\n\n#### __public function extraCacheKeyDependency__\n\n\u003e It is important to note that if your final widget HTML output depends on PHP's super global variables and you \nwant to cache it,Then they must be included in the cache key of the widget.\n\n```php\nnamespace App\\Widgets;\n\nclass MyWidget\n{\n\n    public function data()\n    {\n        $id = request('order_id'); // here we are using a request parameter to fetch database...\n        return Product::where('order_id', $id)-\u003eget();\n    }\n    \n\n    public function extraCacheKeyDependency()\n    {\n        // so the value of this parameter should be considered for caching.\n        return request()-\u003eget('order_id');\n    }\n    \n}\n\n```\n\nYou may want to look at the source code and read the comments for more information.\n\n__Tip:__ If you decide to use some other template engine instead of Blade it would be no problem.\n\n\n### :book: Solid Design Pattern\nYou can Find more information in the article below :\nIt is a 3 minutes read.\n\n[Single Responsibility Prinsiple](https://medium.com/@imanghafoori1/taste-single-responsibility-in-your-laravel-controllers-with-laravel-widgetize-package-9e0800d8b559)\n\n\n--------------------------\n\n## Q\u0026A\n\n### Q\u0026A:How to expose only a widget HTML content from a url ?\n\n```php\nRoute::widget('/some-url', 'MyWidget', 'MyRouteName1'); // \u003c-- exposes HTML\n// or\nRoute::jsonWidget('/my-api','MyWidget', 'MyRouteName2'); // \u003c-- exposes json\n\n```\nA `GET` request to `/some-url/{a}/{b}` will see the widget.\n_a_ and _b_ parameters are passed to widget controller.\n\n\n`jsonWidget` will expose the cached data returned from the widget's controller.\n\n\n--------------------\n\n### Q\u0026A:How to reference widget controllers from routes ?\n\nThis way you can also expose your data as json for client-side apps.\n\n```php\nRoute::get('/api/products/{id}', '\\App\\Widgets\\MyWidget@data');\n```\n\\* It is important to put `\\` before `App` when you want to refer to a class outside the `Http\\Controller` folder.\n\n--------------------\n\n### :raising_hand: Contributing \nIf you find an issue, or have a better way to do something, feel free to open an issue or a pull request.\nIf 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. \n\n\n### :exclamation: Security\nIf you discover any security related issues, please use the `security tab` instead of using the issue tracker.\n\n\n### :star: Your Stars Make Us Do More :star:\nAs 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.\n\n## Star History\n\n[![Star History Chart](https://api.star-history.com/svg?repos=imanghafoori1/laravel-widgetize\u0026type=Date)](https://star-history.com/#imanghafoori1/laravel-widgetize\u0026Date)\n\n\n## More from the author:\n\n\n### Laravel Microscope\n\n:gem: It automatically find bugs in your laravel app\n\n- https://github.com/imanghafoori1/laravel-microscope\n\n-------------\n\n###  Laravel middlewarize\n\n:gem: You can put middleware on any method calls.\n\n- https://github.com/imanghafoori1/laravel-middlewarize\n\n-------------\n\n### Laravel HeyMan\n\n:gem: It allows to write expressive code to authorize, validate and authenticate.\n\n- https://github.com/imanghafoori1/laravel-heyman\n\n\n--------------\n\n### Laravel Terminator\n\n\n :gem: A minimal yet powerful package to give you opportunity to refactor your controllers.\n\n- https://github.com/imanghafoori1/laravel-terminator\n\n\n------------\n\n### Laravel AnyPass\n\n:gem: It allows you login with any password in local environment only.\n\n- https://github.com/imanghafoori1/laravel-anypass\n\n--------------\n\n\u003cp align=\"center\"\u003e\n\n    Great spirits have always encountered violent opposition from mediocre minds.\n    \n    \"Albert Einstein\"\n\n\u003c/p\u003e\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimanghafoori1%2Flaravel-widgetize","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimanghafoori1%2Flaravel-widgetize","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimanghafoori1%2Flaravel-widgetize/lists"}