I need to access some data (User details) in most views. What I have done:
I created ComposerServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
view()->composer(
['includes.header','profile'],
'App\Http\ViewComposers\CustomerComposer'
);
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
Created CustomerComposer class
<?php
namespace App\Http\ViewComposers;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use Modules\Customers\Entities\CustomerDetail;
class CustomerComposer
{
public $customer = [];
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$user = Auth::guard('customer');
$this->customer = CustomerDetail::where('user_id',$user->id())->first();
$view->with( 'customer', $this->customer );
}
}
Everything works but when I look at Debug bar it shows me same queries excecuted per view, so for example if I define ['includes.header','profile'] Same SQL will be excecuted twice if ['includes.header','profile','something_else'] 3 times and so on...
In this case query's is
select * from `customer_details` where `user_id` = '1' limit 1
select * from `customer_details` where `user_id` = '1' limit 1
If I provide wildcard in
view()->composer(
['*'],
'App\Http\ViewComposers\CustomerComposer'
);
It will generate 23 queries! I missed something here?
Ok I think I found solution. In ComposerServiceProvider class:
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(\App\Http\ViewComposers\CustomerComposer::class);
}
That it.
In Laravel Docs
Registering A Singleton
Sometimes, you may wish to bind something into the container that
should only be resolved once, and the same instance should be returned
on subsequent calls into the container:
Per the manual at https://laravel.com/docs/5.5/views#view-composers:
"View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location."
(emphasis mine)
In this case:
view()->composer(
['includes.header','profile'],
'App\Http\ViewComposers\CustomerComposer'
);
you're attaching the includes.header view and the profile view, which I guess includes the includes.header view. So, since the composer is executed when the view is rendered, it'll execute twice, one when rendering of the profile view and again another when rendering the includes.header view.
You can use config here to resolve multiple times query run issue for view compose. For example show below code.
public function compose(View $view)
{
if(!Config::has('composeVars'))
{
Config::set('composeVars') = [
'users' => User::all();
];
}
$view->with('*', Config::get('composeVars'));
}
Related
I'm using a package with cities and countries in my Laravel project. I set up a repository pattern to use this cities data. My plan is to send the cities data to the register view or any other view I want. In the example here I want to send to the project.create page. I tested the repository and when I look through the controller, I can pass the data to the view and print it with dd(). There is no problem with this. Now I want to send this data to a view i want via viewcomposer.
First of all, I wrote a ComposerServiceProvider.php file as follows
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
View::composer(
'project.create',
'App\View\Composers\LocationComposer'
);
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
Then I wrote the composer file, which is as follows:
<?php
namespace App\View\Composers;
use App\Repository\Eloquent\LocationRepository;
use Illuminate\View\View;
class LocationComposer
{
/**
* #var LocationRepository
*/
public $locationlist;
/**
* LocationComposer constructor.
* #param LocationRepository $locations
* #return void
*/
public function __construct(LocationRepository $locations)
{
$this->locationlist = $locations->getAllCities();
}
/**
* Bind data to the view.
*
* #param \Illuminate\View\View $view
* #return void
*/
public function compose(View $view)
{
$view->with('cities', $this->locationlist);
}
}
But the data does not pass to the view I want.
this is the error i got
Things I've tried and done:
-I registered the composerserviceprovider via app config.
-I ran php artisan config:clear
-I tried to send to other views Welcome, register etc.
I suspect I am not invoking the repository correctly into composer.
Thanks for your help...
Probabaly you didn't add App\Providers\ComposerServiceProvider::class into your config/app.php file. All additional service providers need to be added into providers array of config/app.php file.
With Laravel & Eloquent, if a column called status changes its value to "complete," for example, is it possible to automatically change the value of another column (issue_id) to NULL?
I was wondering about the set attribute or intercepting the save() method, but not sure which is best.
You could make use of Observers.
For example, to observe the Issue model, you could generate an Observer as such:
php artisan make:observer IssueObserver --model=Issue
This will produce an observer where you could listen to many model events.
<?php
namespace App\Observers;
use App\Issue;
class IssueObserver
{
/**
* Handle the Issue "updating" event.
*
* #param \App\Issue $Issue
* #return void
*/
public function updating(Issue $issue)
{
if($issue->status == 'complete') {
$issue->issue_id = null;
}
}
}
To register the Observer, you would need to add this to AppServiceProvider#boot()
<?php
namespace App\Providers;
use App\Issue;
use App\Observers\IssueObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Issue::observe(IssueObserver::class);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
You could also just do this in your App/Issue model.
public static function boot()
{
parent::boot();
static::updating(function ($issue) {
if($issue->status == 'complete') {
$issue->issue_id = null;
}
})
}
Obviously, you would need to listen on the events that suit your needs. This is just an example. You could take a look at all the available model events here.
When a record gets deleted from my_items_table I want to insert the record into my_items_table_archive.
I could do this on each Controller, but would prefer to hook into the Eloquent model.
Is there anything like this?
Pseudocode:
class MyItem extends Model {
protected function beforeDelete($record) {
MyItemArchive::create($record); // add record the archive
return true; // continue deletion of $record
}
}
Any idea? Thanks!
Yes, there is something similar to your pseudocode.
You can utilise Eloquent Events
A good example of this can be seen below:
protected $dispatchesEvents = [
'deleted' => UserDeleted::class,
'deleting' => UserDeleting::class
];
The class in question just needs to adhere to / Follow: Listeners
You can also use Eloquent Observers / the observer pattern to achieve a similar result.
Let me know how you get on!
First of all create a new Observer using
php artisan make:observer MyItemObserver
Then
<?php
namespace App\Observers;
class MyItemObserver
{
public function deleting(MyItem $myItem)
{
/// insert new record here
}
}
Now you in your appServiceProvider
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
MyItem::observe(MyItemObserver::class);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
Now your obverserver will be hooked to Model Events.
Hope this helps.
As described in the official documentation you have two choices using the events. The first one is creating an observer like this:
class MyModelObserver
{
/**
* Listen to the Model deleting event.
*
* #param User $user
* #return void
*/
public function deleting(User $user)
{
// HERE YOUR CODE TO TRANSFER THE MODEL
}
}
Than you have to register it on your AppServiceProvider
public function boot {
MyModel::observe(MyModelObserver::class)
}
Otherwise you can add these events in your model by generating the specific class:
protected $dispatchesEvents = [
'deleting' => MyModelDeletingEvent::class,
];
Anyway if you're using a version of laravel lower than 5.4 you should check the documentation for the specific implementation, since the $dispatchesEvents is not available as variable.
I have a part of site that starts with specific prefix /manage.
Can I somehow like with AppServiceProvider view-composers inject a variable in all routes from that prefix?
I tried to do it by passing this variable to layout of all that routes. But then I met a problem. I use this variable in blade view of specific page, and it returns me variable not defined.
Then, I inspect laravel debugger and saw the order of loading of blade files. And it was :
1. Current page view
2. Layout view
3. Sidebars and other stuff
So, the fact that current page is loaded before layout, cause error of undefined variable.
So, how can I solve that ? Thanks.
Code from my Service provider :
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\CT;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer(['website.implicare.ct.show', 'website.implicare.ct.petition.index', 'layouts.ct'], function($view) {
$ct = request()->ct;
$permissions = [];
foreach($ct->userPermissions(auth()->id()) as $userPermission) {
if($userPermission->pivot->ct_id == $ct->id) {
array_push($permissions, $userPermission->name);
}
}
$view->with('permissions', $permissions);
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
create ComposerServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public $theme = 'mytheme';
public function boot()
{
view()->composer($this->theme.'.includes.navbar', 'App\Http\ViewComposers\MenuComposer');
view()->composer($this->theme.'.includes.header', 'App\Http\ViewComposers\MenuComposer');
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
First of all, I have to tell that I am totally new on Laravel, so if you thing I am in the wrong way, please correct me.
Notice, that I have the Laravel 5.1 installed on my application.
I creating an application and I like to have my breadcrumbs inside an array, so I decide to create a Service Provider, and the code for the Service Provider is the following:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
class BreadCrumbsServiceProvider extends ServiceProvider
{
// This will contain all the breadcrumb crumbs
protected $crumbs = [];
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->createBreadcrumb();
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(
'crumbs',
function() {
return $this->crumbs;
}
);
}
protected function createBreadcrumb( ) {
dd( Route::current() );
}
}
So ,when I run my site, the dd returns just null. Can someone help me with this situation ?
Inside your service provider class Route::Class won't work. Try these for
current request uri - $this->app->request->getRequestUri()
Current request method - $this->app->request->getMethod()