I have a few things that I want to present on every page, like $gameAccounts = Auth::user()->gameAccounts()->get();
What would be the best approach to present this variable globally, on each page?
If you need it only for the views you can use a view composer in your AppServiceProvider
public function boot()
{
View::composer('layouts.base', function ($view) {
$view->with('gameAccounts', Auth::user()->gameAccounts);
});
}
If you need it globally you can store it in a config also in AppServiceProvider.
For shared functionality I would recommend to write a trait. The trait can be used throughout your controllers and provide the same functionality for all.
Example:
trait GameSettingsTrait
{
public function getUserGameAccounts()
{
return Auth::user()->gameAccounts()->get();
}
}
In your controller do:
class IndexController extends Controller
{
use GameSettingsTrait;
...
Another approach would be to put the logic in the base controller in app/Http/Controllers/Controller.php. Btw, there you can see that it already uses traits for other functionality.
You need to use view composer.
Look at the doc.
https://laravel.com/docs/5.2/views#view-composers
Use view composer is a best way to do this.
Just add this rows to your AppServiceProvider.php inside boot method:
public function boot()
{
//
view()->composer('*', function ($view) {
$view->with('user', Auth::user()->gameAccounts()->get());
});
}
Related
I've code in my controller which returns some $data, and I want to refer that in all my blades, I can make routes for each page, but I don't like this way. I thought should be better if I refer this $data on layout.blade which include navbar, and etc..., but is it a possible to make route without url? cause I don't want to appear my layout.blade, So my question is, what is a best way to get $data on each blade?
You may perhaps want a view composer. A view composer is an extension of a blade via php that runs before the blade.
In app service provider you set the view you want to view composer class.
use Illuminate\Support\Facades\View;
use App\Http\ViewComposers\LayoutComposer;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
View::composer('layout', LayoutComposer::class);
}
}
Then write your logic in the class.
use Illuminate\View\View;
class LayoutComposer
{
public function compose(View $view)
{
$data = Model::where('id',###)->first();
return $view->with(['data' => $data]);
}
}
https://laravel.com/docs/7.x/views#view-composers
I have to call the method of another controller.
I use following code to make a call.
app('App\Http\Controllers\ApiUserController')->getList();
This is working fine.
But I want to try using use function so that I dont have to repeat all line
use App\Http\Controllers\ApiUserController;
class MyMethods
{
public function index()
{
app('ApiUserController')->getList()
Did I made some mistake here?
Instead of using app function, you will need to go through OOP way like so:
use App\Http\Controllers\ApiUserController;
class MyMethods
{
public function index()
{
$apiUserController = new ApiUserController();
$apiUserController->getList();
However, as many people have mentioned here, it is not really the best practice to call a method of one controller from the another.
So if I were at your place, I would create a helper, register its alias in config and use that helper to get the list in both places.
I hope it helps
Calling controller from other controller or other objects is not a good practice. Here is a good article explaining why. Also "fat" controllers is less preferable than "thin" controllers.
You should define a service layer object with common logic and use it. Create a service object and register it with one of service providers.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\Services\YourUserService;
class AppServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(YourUserService::class);
}
}
After that you can use your service in DI style.
use App\Services\YourUserService;
class MyMethods
{
protected $userService;
public function __construct(YourUserService $userService)
{
$this->userService = $userService;
}
public function index()
{
$this->userService->foo();
}
}
Why should I use dependency injection?
I agree with the answer Learner has given above, however, I wouldn't recommend it in terms of code organisation and testability.
Looking at the code, I can see that you need to get list of users and thats why you have to call the api user controller from another controller. However, you can easily extract the logic out to a service or even a trait.
if you were to use a trait then you could do some thing like following,
trait ApiUser {
public function getList()
{
// get the list for users from api
}
}
//Then you can simply use this trait any where you want,
class SomeController
{
// correct namespace for ApiUser trait
use ApiUser;
}
Another way of doing it, which i love to use again and again depending on the scenario; is to stick with the principle of coding to interface not to implementation. That would be some thing like follow.
interface ApiUserInterface
{
public function getList();
}
class ApiUser implements ApiUserInterface
{
public function getList()
{
// logic to get users from api
}
}
Make sure that when application requires the interface, it knows where to find its implementation. If you using Laravel, then you could register your interface to class in AppServiceProvider
Once that's done, you can use this service any where you want as a contract.
class OneController
{
protected $apiUserContract;
public function __construct(ApiUserInterface $apiUserContract)
{
$this->apiUserContract = $apiUserContract;
}
public function index()
{
// You can retrieve the list of the contract
$this->apiUserContract->getList();
}
}
// you could also just typehint the contact in method without requiring
// it in constructor and it will get resolved out of IOC i.e. container
class AnotherController
{
public function index(ApiUserInterface $apiUserContract)
{
// You can retrieve the list of the contract
$apiUserContract->getList();
}
}
Let me know if you need further explanation and hope it helps
I'm using Laravel 5.5 and trying to get used to code by psr-2 standard (just started learning). I analyze all my code with Quafoo QA and go step by step fixing the errors and record them.
By using facades i get this error "Avoid using static access to class". Because of it i'm trying to avoid using them.
On my controller i have this code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Events\FileLoaded;
use Illuminate\Support\Facades\Input;
use Illuminate\Auth\Middleware\Authenticate;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use \Illuminate\Contracts\View\Factory as ViewFactory;
class LoadDataController extends Controller
{
public function index()
{
$viewfactory = app(ViewFactory::class);
return $viewfactory->make('LoadData/index');
}
//more code
}
Besides the View Facade i also use DB, Input, Validator and Storage
Is this the correct way, are there others?
You don't need to avoid Facades - they are a key part of the framework. But if you want to, you can use dependency injection to include the classes you need as arguments in the controller methods:
class LoadDataController extends Controller
{
public function index(ViewFactory $viewFactory)
{
return $viewfactory->make('LoadData/index');
}
//more code
}
Or if you need that in all the controller methods:
class LoadDataController extends Controller
{
private $viewFactory;
public function __construct(ViewFactory $viewFactory)
{
$this->viewFactory = $viewFactory;
}
public function index()
{
return $this->viewFactory->make('LoadData/index');
}
//more code
}
Of course, this doesn't actually change the functionality of the code you've written, it just rearranges it. I wouldn't take the word of the code analyzer you mentioned as something you are doing wrong. These are standard patterns to use in Laravel.
In several controllers i have to use the same method to show results as table with column sorting functionality:
public function showSearchResults(Request $req){
$query=Service::where('title', $req->search);
// Columns sorting
if ($req->has('order')){
$order= $req->order=='asc' ? 'asc' : 'desc';
$order_inverse=$req->order=='asc' ? 'desc' : 'asc';
} else {
$order='desc';
$order_inverse='asc';
}
...
$url=$req->url().'?'.http_build_query($req->except('sortby','order','page'));
$results=$query->with('type')->paginate(15)->appends($req->all());
return View::make('services.search_results')
->with('results', $results)
->with('url',$url)
->with('sortby', $sortby)
->with('order', $order)
->with('order_inverse', $order_inverse);
}
What is the best approach to avoid DRY in such case?
Sharing methods among Controllers with Traits
Step 1: Create a Trait
<?php // Code in app/Traits/MyTrait.php
namespace App\Traits;
trait MyTrait
{
protected function showSearchResults(Request $request)
{
// Stuff
}
}
Step 2: use the Trait in your Controller:
<?php // Code in app/Http/Controllers/MyController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Traits\MyTrait; // <-- you'll need this line...
class MyController extends Controller
{
use MyTrait; // <-- ...and also this line.
public function getIndex(Request $request)
{
// Now you can call your function with $this context
$this->showSearchResults($request);
}
}
Now you can use your Trait in any other controller in the same manner.
It is important to note that you don't need to include or require your Trait file anywhere, PSR-4 Autoloading takes care of file inclusion.
You can also use Custom Helper classes as others have mentioned but I would recommend against it if you only intend to share code among controllers. You can see how to create custom helper classes here.
You can use traits (as ventaquil suggested) or you can create custom helpers file and add helpers there.
After that, you'll be able to use this helper from any class (controllers, models, custom classes, commands etc) like any other Laravel helper.
Use traits? More available here: http://php.net/manual/en/language.oop5.traits.php
You can create a helper file in your app directory. for eg. MethodHelper.php
In this file you can mention the method that you require using anywhere.
For instance,
<?php namespace App;
class MethodHelper
{
public static function reusableMethod()
{
//logic
}
}
You can use this method anywhere, by using the namespace and calling the method.
In the above eg.
The namespace would be:
The method call function would look like:
MethodHelper::reusableMethod();
You can send parameters too based on your functional requirements.
In your eg. you could have
public function showSearchResults(Request $req){
//
}
instead of reusableMethod().
Your call would be:
MethodHelper::showSearchResults($req);
I wanna ask about design pattern.
Why should I use dependency injection in constructor, not import it ('use statement')?
For example:
in my controller:
class AuthController extends Controller {
public function __construct(UserGateway $userGateway)
{
$this->userGateway = $userGateway;
}
public function doSomething()
{
$this->userGateway->foo();
}
}
Why don't use just like this instead?
use Acme\UserGateway;
class AuthController extends Controller {
public function doSomething()
{
UserGateway::foo();
}
}
Many thanks.
Assuming UserGateway is not laravel facade: here's the biggest advantage of injecting stuff this way: in the future, you might redefine what UserGateway actually is, and supply some other class (most often, it's subclass) instead of it like this:
$this->app->bind(UserGateway::class, function ($app) {
return new NewUserGateway();
});
This is extremely useful for overriding some parts of your code, especially if you're using same packages across multiple projects. And it does not require you to change the AuthController's code.
If UserGateway is a Facade, the only benefit you'll get is a better code navigation with you IDE, since it will know what class exactly are you referencing (assuming that you didn't re-bound it).