Pass data to all routes? - laravel

I use a set of data on every route. Is there a way to pass this data to all routes without having to specify the data under each route, like:
Route::get('/', function()
{
$data = Data::all();
return View::make('index')->with('data', $data);
});
Route::get('/another', function()
{
$data = Data::all();
return View::make('another')->with('data', $data);
});

You can use view()->share() in a service provider, like so :
view()->share('key', 'value');
You will then be able to access value using {{ key }} in all your views.
You can put it in the boot() method of the default AppServiceProvider.

Use view composers.
View::composer('profile', function($view)
{
$view->with('count', User::count());
});
Now each time the profile view is rendered, the count data will be bound to the view.
Also you need assign composer to many views, so you can just use ['profile', 'dashboard'] instead of 'profile'.
Or you can share a data with one function:
View::share('name', 'Steve');

Related

Laravel 8: Storing custom route attributes

What is the most simple way to store custom attributes such as page titles or other key value pairs that may be attached to a route?
For example, say I want to add my own metadata data to:
Route::get('/themetest', [MyController::class, 'list'])->name('themetest');
I thought I could add a route macro to save metadata to be retrieved later using an addMetadata method like
Route::get('/themetest', [MyController::class, 'list'])->name('themetest')->addMetadata('title' => 'Page Title');
Is that possible? Doesn't seem like it is.
Is there a standard way to store this type of info? Or, any practical way? I thought maybe I could store them using default(), but that could change the default parameters for a controller function.
You could use the 'action' array of the Route to store this information if you had to:
// In a Service Provider # boot
Illuminate\Routing\Route::macro('addMetaData', function ($key, $value) {
$this->action['meta'][$key] = $value;
return $this;
});
Illuminate\Routing\Route::macro('getMetaData', function ($key = null) {
return is_null($key)
? $this->getAction('meta')
: $this->getAction('meta.'. $key);
});
// Route definition
Route::get('/themetest', [MyController::class, 'list'])
->name('themetest')
->addMetaData('title', 'Page Title');
// Controller method (Route action)
public function list(Request $request)
{
dump($request->route()->getMetaData('title'));
}

Undefined Variable in Laravel 8 view

I just want to Pass a Variable to the views about page.
This is the controller file
public function about(){
$name ="maneth";
return view::make('about')->with('name', $name);
}
This is the about page
#switch($name)
#case(1)
#break
#case(2)
#break
#default
#endswitch
This is the web file
Route::get('/about',function(){
return view('about',[PagesController::class, 'about']);
});
The Error is $name is undefined
I'm Using Laravel Framework 8.75.0
and PHP 7.3.33
You are using callback in router's file and there you not sent the name variable,
You can bind controller and router file using :
Route::get('/about', [AboutController::class, 'about']);
Your controller action is never being executed as your route definition is returning a view directly.
Change your route so that it calls your controller and action.
Route::get('/about', [AboutController::class, 'about']);
As long as it doesn't require any real logic (database query etc.) you can do it with a closures in your route. Otherwise you have to call the controller from your route. This would look like this:
Route::get('/about', [AboutController::class, 'about' ])->name('about');
And this would be thee closures style:
Route::get('/about',function(){
$name = 'Slim Shaddy';
return view('about', ['name' => $name]);
});

Create a route that has uri-segment

I tried to call a function on the controller and the function I have created a route, but how to create a route that has uri-> segement ?
Example
$route['select-item'] = 'select_item';
Controllers
function select_item() {
$item = $this->uri->segment(3);
$data = array ('get_item' => $this->Model->My_item($item));
$this->load->view('Myview');
}
Views
<?php echo $row->item;?>
I suggest you use codeigniters wildcards on routes, You can go ahead and set your route to:
$route['select-item/(:any)'] = 'select_item/$1';
then on your controller, just do:
function select_item($item) {
$data = array ('get_item' => $this->Model->My_item($item));
$this->load->view('Myview',$data);
}
And the link in your view should work properly.

Laravel Ajax controller with single route

Just wondering if this is a good way to write ajax code to interact with Laravel routes?
Example my application's require to list all customer data and also list all country through ajax. I have 3 controller ApiController, CustomerController, CountryController.
So in my routes.php I have this routes
Route::get('api/v1/ajax/json/{class}/{function}', 'Api\v1\ApiController#ajaxreturnjson');
In the ApiController.php, I have below function to call other controller function to return the data I need.
class ApiController extends Controller
{
public function ajaxreturnjson(Request $request, $controller, $function){
$input = $request->input();
if($request->input('namespace') != ''){
$namespace = $request->input('namespace');
unset($input['namespace']);
}else{
$namespace = 'App\Http\Controllers';
}
$data = array();
try {
$app = app();
$controller = $app->make($namespace.'\\'.$controller);
$data = $controller->callAction($function, array($request)+$input);
} catch(\ReflectionException $e){
$data['error'] = $e->getMessage();
}
return response()->json($data);
}
}
So example to use the ajax, I just need to pass the class name, namespace and also the function name to the ajax url.
Example to retrieve all customer info.
$.ajax({
dataType:"json",
url:"api/v1/ajax/json/CustomerController/getList",
data:"namespace=\\App\\Http\\Controllers\\",
success:function(data){
}
})
So in this way, I don't have to create so many routes for different ajax request.
But I am not sure if this will cause any security issue or is this a bad design?
Personally, I would not do it this way. Sure, you could do it this way, but it's not very semantic and debugging it could be a pain.
Also, if someone else begins working on the project, when they look at your routes file, they won't have any idea how your app is structured or where to go to find things.
I think it's better to have a controller for each Thing.

Multiple routes to same Laravel resource controller action

I like to use resource controllers in Laravel, as it makes me think when it comes to data modelling. Up to now I’ve got by, but I’m now working on a website that has a public front-end and a protected back-end (administration area).
I’ve created a route group which adds an “admin” prefix, like so:
Route::group(array('before' => 'auth', 'prefix' => 'admin'), function()
{
Route::resource('article', 'ArticleController');
Route::resource('event', 'EventController');
Route::resource('user', 'UserController');
});
And I can access the methods using the default URL structure, i.e. http://example.com/admin/article/1/edit.
However, I wish to use a different URL structure on the front-end, that doesn’t fit into what resource controllers expect.
For example, to access an article, I’d like to use a URL like: http://example.com/news/2014/06/17/some-article-slug. If this article has an ID of 1, it should (under the hood) go to /article/1/show.
How can I achieve this in Laravel? In there some sort of pre-processing I can do on routes to match dates and slugs to an article ID, and then pass that as a parameter to my resource controller’s show() method?
Re-visiting this, I solved it by using route–model binding and a pattern:
$year = '[12][0-9]{3}';
$month = '0[1-9]|1[012]';
$day = '0[1-9]|[12][0-9]|3[01]';
$slug = '[a-z0-9\-]+';
// Pattern to match date and slug, including spaces
$date_slug = sprintf('(%04d)\/(%02d)\/(%02d)\/(%s)', $year, $month, $day, $slug);
Route::pattern('article_slug', $date_slug);
// Perform the route–model binding
Route::bind('article_slug', function ($slug) {
return Article::findByDateAndSlug($date_slug);
});
// The actual route
Route::get('news/{article_slug}', 'ArticleController#show');
This then injects an Article model instance into my controller action as desired.
One simple solution would be to create one more route for your requirement and do the processing there to link it to the main route. So, for example:
//routes.php
Route::get('/arical/{date}/indentifier/{slug}', array (
'uses' => 'ArticleController#findArticle'
));
//ArticleContoller
public function findArticle($date,$slug){
$article = Article::where('slug','=','something')->first(); //maybe some more processing;
$article_id = $article->id;
/*
Redirect to a new route or load the view accordingly
*/
}
Hope this is useful.
It seems like if Laravel 4 supports (:all) in routing, you would be able to do it with ease, but unfortunately (:all) is not supported in Laravel 4.
However, Laravel 4 allows detecting routes by regular expression, so we can use ->where('slug', '.*').
routes.php: (bottom of the file)
Route::get('{slug}', 'ArticleController#showBySlug')->where('slug', '.*');
Since Laravel will try to match the top most route in routes.php first, we can safely put our wildcard route at the bottom of routes.php so that it is checked only after all other criteria are already evaluated.
ArticleController.php:
class ArticleController extends BaseController
{
public function showBySlug($slug)
{
// Slug lookup. I'm assuming the slug is an attribute in the model.
$article_id = Article::where('slug', '=', $slug)->pluck('id');
// This is the last route, throw standard 404 if slug is not found.
if (!$article_id) {
App::abort(404);
}
// Call the controller's show() method with the found id.
return $this->show($article_id);
}
public function show($id)
{
// Your resource controller's show() code goes here.
}
}
The code above assumes that you store the whole URI as the slug. Of course, you can always tailor showBySlug() to support a more advanced slug checking.
Extra:
You could also do:
Route::get('{category}/{year}/{slug}', 'ArticleController#showBySlug')->where('slug', '.*');
And your showBySlug() would just have additional parameters:
public function showBySlug($category, $year, $slug)
{
// code
}
Obviously you can extend to month and day, or other adaptations.

Resources