I'm trying to use the views of my custom package without adding them to view.php conf file. I have created the following service provider and added it to app.php file.
class FooServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadViewsFrom(__DIR__.'/../views', 'foo');
}
public function register()
{
}
}
I tried to use a package view by view('foo.test'). The view file is located in 'packages/foo/bar/views/test.blade.php'. However Laravel can not yet find the view file. Is there anything more I need to do? BTW, I do not need to publish view files to resource/views folder.
Once you have loaded the views in boot as you are doing right now:
class FooServiceProvider extends ServiceProvider
{
public function boot()
{
$this->loadViewsFrom(__DIR__.'/../views', 'foo');
}
public function register()
{
}
}
Check your service provider loads from the appropriate folder as right now you are having packages/foo/bar/views/teset.blade.php so your service provider needs to be in packages/foo/bar/providers it can be providers or any other folder name just quoted for example and please make sure about the spell check, you are having blade file named teset and you are calling test then finally you can call this view in controller with something like this:
return ('foo::test')
Update:
Well as per the requirement you need to make changes in config on fly then this you need to have service provider something like this:
use Illuminate\View\FileViewFinder;
use Illuminate\View\ViewServiceProvider;
class WebViewServiceProvider extends ViewServiceProvider
{
/**
* Register View Folder
*
* #return void
*/
public function registerViewFinder()
{
$this->app->bind('view.finder', function ($app) {
$paths = 'your view directory';
return new FileViewFinder($app['files'], array(base_path($paths)));
});
}
}
Hope this helps.
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
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.
I am creating a SAAS application with a single laravel installation and multi tenant database.
So i have a main DB that is connected to laravel by default. the client can access the application through their sub-domain like: client1.example.com and client2.example.com
I am saving all info fo the client like domain and db name in the main db.
How can change the DB according to the subdomain
I tried with the following Code
in routes/web.php
Route::group(['domain' => '{account}'], function() {
Route::get('/', function($account) {
// This will return {account}, which you can pass along to what you'd like
return $account;
});
});
in app/Providers\RouteServiceProvieder.php
public function boot(Router $router)
{
parent::boot($router);
$router->bind('domain', function ($value) {
//$hst=$request->getHost();
$domain= Customer::where('sub_domain',$value)->first();
if ($domain) {
return $domain;
}
throw new Exception('error message');
});
}
Then i have created a ServiceProvider ConfigServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Request;
class ConfigServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register(Request $request)
{
$customer=$request->route('domain');
//$customer = Request::route('domain'); // there are multiple ways of doing this
//$customer = $request->route()->domain;
config([
'database.mysql.database' => $customer->customer_database, //this is because I have same username and password for all the databases. If you have different username and passwords set them too.
]);
DB::reconnect(); // this will help in reconnecting the database if the connection is already established. and import the DB facade.
}
}
But the code is not working?
The Error i am getting is
FatalThrowableError in ConfigServiceProvider.php line 25:
Type error: Too few arguments to function App\Providers\ConfigServiceProvider::register(), 0 passed in C:\xampp\htdocs\main\vendor\laravel\framework\src\Illuminate\Foundation\Application.php on line 568 and exactly 1 expected
I am using Laravel 5.4. Can any one guide me how to do it correctly?
well there are some issues here:
First the register() method of a service provider should not accept a Request instance as argument. Its better to write it like that:
public function register()
Second, dont use config() in the register() method, from the laravel docs:
within the register method, you should only bind things into the
service container. You should never attempt to register any event
listeners, routes, or any other piece of functionality within the
register method. Otherwise, you may accidentally use a service that is
provided by a service provider which has not loaded yet.
IMHO I would use a middleware to change the database configuration like you tried in a service provider, i.e:
public function handle($request, Closure $next)
{
$customer=$request->route('domain');
if($customer)
{
config(['database.mysql.database' => $customer->customer_database]);
DB::reconnect();
}
return $next($request);
}
If you take care of loading the middleware in the right place (look in app/Http/Kernel.php) you will have database changed before any query.
What I would suggest is to create 2 .env files, one for each subdomain e.g. .env.domain1 and .env.domain2
Then in your app service provider:
public function boot() { //Use boot for this
$fn = ".env.".$this->app->request->route('domain');
$dotenv = new \Dotenv\Dotenv(self::basePath(), $fn);
try {
$dotenv->overload();
} catch (\Dotenv\Exception\InvalidPathException $e) {
//Nothing to overload with
}
}
This makes your sub-domains behave like different environments which does look like what you're trying to do.
Change
use Illuminate\Support\Facades\Request;
to
use Illuminate\Http\Request;
You can not use Facades for dependency/method injection. Hope it helps
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 build a small app using laravel 5.2. I put all of my files into a folder called Surveys located at App/Modules/Surveys. "No worries, I am planning to move the Modules out of the App folder, I just need to get the controller to work"
Currently my controller is located on App/Http/Controllers/SurveysController
I want to move my controller folder so it is located on App/Modules/Surveys/Controllers/Frontend/SurveysController
How would I tell laravel to resolve the controller out of this path App/Modules/Surveys/Controllers/Frontend/ instead of App/Http/Controllers?
I tried to do this into a service provider but it is still not working
<?php
namespace App\Modules\Surveys\Providers;
use Illuminate\Support\ServiceProvider;
class PackageServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
if (! $this->app->routesAreCached()) {
require __DIR__.'/../routes.php';
}
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->app->make('Modules\Surveys\Controllers\Frontend\SurveyController');
}
}
What should I do to make the routes point to the correct controller?
Just for clarity my Application instructor starts at the App
App/Https/Controllers
App/Modules/Surveys
I think I figured it out.
Inside the App/Providers/RouteServiceProvider file, I changed the value of $namespace variable to an empty string like this
Changed the following line
protected $namespace = 'App\Http\Controllers';
To this
protected $namespace = '';
Then inside my routes.php file I used the namespace like this
Route::group([
'namespace' => 'Modules\Vendname\Surveys\Controllers\Frontend',
], function()
{
Route::get('/survey', ['as' =>'survey.index', 'uses' => 'SurveysController#index']);
});
I am not sure why Taylor have the value hard coded in the service provider and not an option in the configs but this solution seems to work!
I would been better if there is a dynamic way to override that value.
By default controller's namespace is App\Http\Controllers which is defined in RouteServiceProvider and has a property $namespace so all controllers are supposed to be inside the App\Http\Controllers controller.
I think you have more modules and not only Surveys module, you can set the RouteServiceProvider's $namespace property to 'App\Modules' and define your routes as:
Route::get('some/route', ['uses' => 'Surveys\Controllers\Frontend\SurveyController#someMethod']);
If you feel that a huge prefix namespace on each route is ugly you could create a ModuleFooRouteServiceProvider for each module and require a file like 'routesModuleFoo.php' the same way as RouteServiceProvicer does and register those service providers on config/app.php file like:
'providers' => [
...
App\Modules\Surveys\SurveysRouteServiceProvider::class,
App\Modules\ModuleFoo\ModuleFooRouteServiceProvider::class,
...
]
And ModuleFooServiceProvider would look like:
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
class ModuleFooServiceProvider extends ServiceProvider
{
protected $namespace = 'App/Modules/ModuleFoo/Controllers';
public function boot(Router $router)
{
parent::boot($router);
}
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routesModuleFoo.php');
});
}
}
And your routes for that module will be defined on routesModuleFoo.php