Using Laravel 5.6, I'm trying to get the number of received links a logged-in user may have in my application.
public function getReceivedLinksCount() {
return $count = App\Link::where([
['recipient_id', Auth::id()],
['sender_id', '!=', Auth::id()]
])->count();
}
So far, so good. Question is not about that piece of code, but where I can use it. I'd like to display this counter on the navigation bar of the website (Facebook's style) which is in my header.blade.php which is included in every page.
I'd like to do it with a clean code, of course. It seems like I need to use View Composers but I'm not sure it's the right way to do it, and not sure on how the code is supposed to look.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer('layouts.header', function ($view) {
$view->with('variable_name', \App\Path-To-Your-Model::something());
});
}
You can share a value across all views by using View::share(), see docs
For example
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$linksCount = Link::getReceivedLinksCount();
View::share('linksCount', $linksCount);
}
...
}
This works well if you want to set the value everywhere. Personally, I would set the value in the constructor of a 'BaseController' that gets extended by other controllers. This makes the code more discoverable because most people would expect view values to be set in a controller. And it's also a bit more flexible if you plan on having a section of your app that doesn't require that value to be computed.
Related
Hello Developers & Coders ,
My question is How to define a global variable , that can be used in
all controllers in Laravel ?
I have defined one variable $company in AppServiceProviders's boot method - that im using in all blade views , but I can not use it in controllers file , it gives error , undefined variable $company
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
Schema::defaultStringLength(191);
$company=DB::table('company')->where('id',1)->first();
View::share('company',$company);
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
please guide me , thanks for your efforts & time :)
set configuration variables at runtime
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
Schema::defaultStringLength(191);
$company=DB::table('company')->where('id',1)->first();
// View::share('company',$company);
config(['yourconfig.company' => $company]);
}
}
usage:
config('yourconfig.company');
Okay, so unless you want to keep it in your Session, which I absolutely do not recommend, Cache which does not seem to be a best idea either or set it through the Config system inside of a Framework (which already are 3 different solutions suited for different matters) I would start from thinking what that variable will contain, if that's something that's just a Collection of Company model then you can basically use it in any controller by just using Laravel Eloquent methods.
What I recommend is either $company = Company::where('foo', 'bar')->first();, or just some data provider that would return all the information that you need in the form of Laravel Collection.
tl;dr
#recommended way that's reusable throughout whole app
Company::find(1); // instead of DB::table('company')->where('id', 1)->get();
Hope that helps.
I have seen a few similar questions to mine, with the common answer being to use a view composer. I have a HomeController that shows articles from a database by passing query data to an associated view, which works see this image link
As you can see there is a nav bar, which is generated by the master layout, layout.master.
For each title in the navigation I am trying to show each article for that section via a for loop which generates the links.
My code is this.
public function index()
{
$loans_articles = Article::byDepartment('Loans')->get();
$digital_articles = Article::byDepartment('Digital')->get();
$consulting_articles = Article::byDepartment('Consulting')->get();
return view('welcome',
[
'loans_articles' => $loans_articles,
'digital_articles' => $digital_articles,
'consulting_articles' => $consulting_articles,
]);
}
As you can see I'm returning this data to the welcome blade.
In my nav bar I tried
#if(count($loans_articles) > 0)
#foreach($loans_articles as $ls)
<!--for each loop which grabs the articles with department Loans-->
<li>{{ $ls->title }}</li>
#endforeach
#endif
But as soon as you navigate away from the home page the nav bar doesn't know what $loans_article is.
Is there a clean way to pass this data to the master blade navigation without sending the same data to every subview?
The way I tend to achieve this is by making a variable available to every view in this way:
All of your controller should extend a base controller, which is usually located in app/Http/Controllers/Controller.php. Inside this controller you can put some code that will be used by all extending controllers.
In this base controller you can make a variable available to all views, like this...
class Controller extends BaseController
{
public function __construct()
{
// Load your objects
$loans_articles = Article::byDepartment('Loans')->get();
// Make it available to all views by sharing it
view()->share('loans_articles', $loans_articles);
}
}
All of your controllers must extend this controller for this to work.
If any of your controllers have their own constructors, you must also make sure to call parent::__construct() to ensure the above code is run. If your controllers don't have their own constructors, you can omit calling parent::__construct().
public class HomeController extends Controller
{
public function __construct()
{
parent::__construct();
// Your constructor code here..
}
}
This way you should be able to use $loans_articles in all of your views.
You must use View Composer to achieve what you are trying to do :
https://laravel.com/docs/5.2/views
if you would like to share data with all of your blade templates, a simple way is trough
appServiceProvider.php and boot method.
you can find this file in app/Providers/AppServideProvider.php and do the changes like bellow:
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
}
}
after that you can access to the value in all blade files using {{ $key }}
note: do not forget to use Illuminate\Support\Facades\View in top of the class
<?php $contact = DB:table('tbl_contact')->get(); ?>
Use this code in master.blade.php in top section
And
Use such as
<a href='{{ $contact[0]->fbLink ? $contact[0]->fbLink : " " }}'>
I am trying to create an application where i have a user activity log. I dont want to write a special function in all the pages. I just want to metnion it once and run on all the pages or controller where ever i go. Which keep showing on the header.blade.php. And i want to keep using that log all time.
I have a function with like this.
public function headerLogs()
{
$latestActivities = Activity::with('user')->latest()->limit(10)->get();
return view('layouts.header')->with('logs', $latestActivities);
}
How can i do that?
Laravel has built-in functionality for that: View Composers. They are what you use if you want some data to be in every view that is loaded (of course you specify which views exactly)
So from the docs we would create a service provider for our view composer:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ActivitiesComposerServiceProvider extends ServiceProvider
{
/**
* Register bindings in the container.
*
* #return void
*/
public function boot()
{
// Using Closure based composers...
view()->composer('layout.header.activity', function ($view) {
$latestActivities = Activity::with('user')->latest()->limit(10)->get();
$view->with('logs', $latestActivities);
});
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
And then you register your ActivitiesComposerServiceProvider service provider by simply adding it to the providers array in config/app.php.
So now you can simply #include('layout.header.activity') and the logs will show with no extra line of code in your controller or view
In your base controller:
view()->composer('layouts.header', function($view){
//your code for header logs which gives $logActivites.
$view->with('logs', $logActivites);
}
So, whenever your view layouts.header will be created, this $logActivites will be available.
Everyone had a situation when one variable had to be accessible in every view (blade) file. One possible solution – letting the service provider load our global view information. For Example, type this in your service provider.
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
// Using view composer for specific view
view()->composer('welcome',function($view) {
$view->with('latestActivities', Activity::with('user')->latest()->limit(10)->get());
});
}
}
Then you can access the latestActivities variable from all you view files
I am working with laravel 5 and I am novice developer so I just learnt how to use the Repository pattern. Now as novices go, I first use the routes.php file to bind my UserRepositoryInterface to DbUserRepository like so:
App::bind('UserRepositoryInterface', 'DbUserRepository');
This is just psuedo, image the namepspaces with the above code too.
So after this I realized that that there is something called a Service Provider which is supposed to contain code like so. Now I refactored this in the AppServiceProvider in my Providers folder and it works fine still.
But since I will be having so many more repositories, is this is a good idea to place them into the AppServiceProvider or should I go ahead and make a dedicated provider for my repositories and bind them there? What is the best way to do this? Is there a standard for this?
So later I got to understand that this all about preference so I coded a RepositoryServiceProvider in which I bind all the repository contracts to the desired implementations like so:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Archive\Repositories\TenantRepository;
use Archive\Repositories\TenantRepositoryEloquent;
use Archive\Repositories\UserRepository;
use Archive\Repositories\UserRepositoryEloquent;
use Archive\Repositories\OrderRepository;
use Archive\Repositories\OrderRepositoryEloquent;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(TenantRepository::class, TenantRepositoryEloquent::class);
$this->app->bind(UserRepository::class, UserRepositoryEloquent::class);
$this->app->bind(OrderRepository::class, OrderRepositoryEloquent::class);
}
}
I'm playing around with packages and I'm able to my code to work (in my controllers) when I do this:
App::make('Assets')->js('bla');
Now I want to set up a static facade so I can do this:
Assets::js('bla');
for this and I'm getting errors. I've been following this blog entry and haven't had any trouble up to this point. But now I'm stuck with a " Call to undefined method" error.
I'm not sure what code you'd need to see, so here's everything: https://github.com/JoeCianflone/msl/tree/jc-working
Specifically here is my workbench: https://github.com/JoeCianflone/msl/tree/jc-working/workbench/Joecianflone/Assets
And here is the controller where I was messing around with it: https://github.com/JoeCianflone/msl/blob/jc-working/app/controllers/HomeController.php
Any help greatly appreciated.
Looks like it was an issue with namespacing, I got it working by changing this:
<?php namespace Joecianflone\Assets\Facades;
use Illuminate\Support\Facades\Facade;
class Assets extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Assets'; }
}
to this:
class Assets extends \Illuminate\Support\Facades\Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'Joecianflone\Assets\Assets'; }
}
What I'm not sure about is why the code from the tutorial worked but mine didn't. I must have skipped a step.
Just a sidenote, if you plan to share your code with the communuty (please do) i encourage you to use 5.3 syntax. Laravel requirements is 5.3 so dont use 5.4 in your package.