Laravel 5 - Route not available in notFoundHttpException - laravel

Currently I'm experiencing an error I find hard to fix. The error concerns the \Request::route() returning NULL when the notFoundHttpException is fired and my custom error view is rendered.
The problem is that my application needs the current route in order to do a variety of things. I think it is "normal" that ..::route() returns NULL since the route does not exists.
This is where I show my custom error view:
// App\Exceptions\Handler
return response()->view('layouts.default', [
'main_content' => view('errors.'.$e->getStatusCode())
], $e->getStatusCode());
When I call \Request::route() inside my view it returns NULL.
Anyone has any idea how to solve this in a clean way?
Edit
The application I am currently working on is a multi domain system. The route is needed to determine what domain is currently requested.
All routes are wrapped inside one group:
Route::group(['domain' => {domain}.{tld}], function()
{
// Application routes...
}
To determine the domain:
$domain = \Request::route()->domain;
$tld = \Request::route()->tld;
// Retrieve from database...
Yes there are work arounds like:
// Url requested: mydomain.com/notexistingpage
$url_parameters = #explode(".", $_SERVER['HTTP_HOST']);
$domain = $url_parameters[0];
$tld = $url_parameters[1];
// Retrieve from database...
However I would like to keep using the router to serve the parameters. I'll mark this question as answered.

Try this
\Route::getFacadeRoot()->current()->uri();
or
\Route::getCurrentRoute();

A work around could be:
// Url requested: mydomain.com/notexistingpage
$url_parameters = #explode(".", $_SERVER['HTTP_HOST']);
$domain = $url_parameters[0];
$tld = $url_parameters[1];
// Retrieve from database...

Related

How to render a cms page with default theme AND variables from controllers in OctoberCMS?

I'm wondering how I can render a view, or display a page with my default theme in OctoberCMS, via a route that executes a function in a controller.
If I have the following route:
Route::get('bransje', [
'uses' => 'Ekstremedia\Cityportal\CPController#bransje'
]);
And in my controller CPController ive tried several things, like I used to with Laravel:
public function bransje() {
$stuff = Stuff::with('info');
return View::make('cms::bransje')->with('stuff',$stuff);
}
But I cannot seem to get it to work, and I've tried to search the web, but it's hard to find answers. I have found a workaround, and that is to make a plugin component, then I can include that component and do:
public function onRun()
{
$this->eventen = $this->page['stuff'] = $this->stuff();
}
protected function stuff()
{
return ...
}
Is there any way so I can make pages without using the Cms, and that are wrapped in my default theme? I've tried
return View::make('my-theme-name::page');
and a lot of variants but no luck.
I know I can also do a:
==
public function onRun()
{
}
in the start of my page in the cms, but I'm not sure how to call a function from my plugin controller via there.
You can bypass frontend routing by using routes.php file in your plugin.
Full example in this video turotial.
If this answer can still be useful (Worked for October v434).
I have almost the same scenerio.
What I want to achieve is a type of routing like facebook page and profile.
facebook.com/myprofile is the same url structure as facebook.com/mypage
First I create a page in the CMS for each scenario (say catchpage.htm)
Then a created a catchall route at the buttom of routes.php in my plugin that will also not disturb the internal working of octobercms.
if (!Request::is('combine/*') && !Request::is('backend/*') && !Request::is('backend')) {
// Last fail over for looking up slug from the database
Route::get('{slug}/{slug2?}', function ($slug, $slug2 = null) {
//Pretend this are our routes and we can check them against the database
$routes = ["bola", "sade", "bisi", "ade", "tayo"];
if(in_array($slug, $routes)) {
$cmsController = new Cms\Classes\Controller;
return $cmsController->render("/catchpage", ['slug' => $slug]);
}
// Some fallback to 404
return Response::make(View::make('cms::404'), 404);
});
}
The if Request::is check is a list of all the resource that october uses under the hood, please dont remove the combine as it is the combiner route. Remove it and the style and script will not render. Also the backend is the url to the backend, make sure to supply the backend and the backend/*.
Finally don't forget to return Response::make(View::make('cms::404'), 404); if the resource is useless.
You may put all these in a controller though.
If anyone has a better workaround, please let us know.

laravel api with vue 2 js not returning data - could 'localhost:8000' (or '127.0.0.1:8000') be the issue?

I am using the repo https://github.com/mschwarzmueller/laravel-ng2-vue/tree/03-vue-frontend so I have 100% confidence in the reliability of the code. I can post through the laravel api endpoint through the very simple Vue client, and also through Postman. Through Postman I can retrieve the table data array, but not so in the client app. In POSTMAN:
localhost:8000/api/quotes
works just fine.
IN THE vue 2 js CLIENT APP:
methods: {
onGetQuotes() {
axios.get('http://localhost:8000/api/quotes')
.then(
response => {
this.quotes = (response.data.quotes);
}
)
.catch(
error => console.log(error)
);
}
returns nothing. returning the response to Console.log returns nothing. The Network/XHR tab shows the table data rows, but I am not sure what that means.
I know for sure that this code works for others with their unique api endpoints, which I assume may not use localhost or '127:0.0.1:1080.
Edit: in response to request for more info
public function getQuotes()
{
$quotes = Quote::all();
$response = [$quotes];
return response()->json($response, 200);
}
and the relevant route:
Route::get('/quotes', [
'uses' => 'QuoteController#getQuotes'
]);
Just to confirm: I am using verified github repo code in which the ONLY change is my api endpoint addressas mentioned in the first line of the body of this question. . Note that the Laravel back end is also derived from a related repo in Max's fine tutorial. The running code can be seen at
So I really don't think this is a coding error- but is it a configuration error due to me using local host??
EDIT: It WAS a coding error in the laravel controller as shown below
The reason your code isn't working if because you haven't provided a key for your $quotes in your controller but you're looking for it in your vue file (response.data.quotes).
[$quotes] is essentially [0 => $quotes] so when the json response comes through it be 0: [...] not quotes: [...].
To get this to work you just need to change:
$response = [$quotes];
to:
$response = ['quotes' => $quotes];
Furthermore, just an FYI, you don't need to provide the 200 in response->json() as it's the default and you can just return an array and Laravel automatically return the correct json response e.g.:
public function getQuotes()
{
$quotes = \App\Models\Artist::all();
return compact('quotes'); //<-- This is just another way of writting ['quotes' => $quotes]
}
Obviously, you don't have to if you don't want to.
Hope this helps!

Laravel 5.3 dynamic routing to multiple controllers

I'm using Laravel 5.3. I have a bunch of urls that I'd like to handle with a single route, to multiple controllers.
e.g.
GET /admin/foo => FooController#index
GET /admin/foo/edit/1 => FooController#edit($id)
GET /admin/bar => BarController#index
GET /admin/bar/edit/1 => BarController#item($id)
GET /admin/baz => BazController#index
GET /admin/baz/edit/1 => BazController#item($id)
etc.
I want to be able to detect if the controller exists, and if not throw a 404 or route to a default controller (which may throw a 404).
Below is what I've got so far, but I'm not sure what I'm doing. Shouldn't I be instantiating the controller using the service container? I don't think I should be hardcoding namespaces like this. And my handling of the id parameter is sketchy. Perhaps I should have two routes for these two patterns or something?
Route::get('/admin/{entityType}/{action?}/{id?}', function ($entityType, $action = 'index', $id = null) {
$controllerClass = 'App\Http\Controllers\\' . ucfirst($entityType) . 'Controller';
$controller = new $controllerClass;
$route = app(\Illuminate\Routing\Route::class);
$container = app(\Illuminate\Container\Container::class);
return (new Illuminate\Routing\ControllerDispatcher($container))->dispatch($route, $controller, $action);
abort(404);
});
I'd recommend you to define a route for every controller explicitly. This is the best way to build a maintainable app.
Also, if using one route and one method is an option (with right architecure it is) use one route:
Route::get('/admin/{entityType}/{action?}/{id?}', 'Controller#method');
And one entry point:
public function method($entity, $action = null, $id = null)
{
// Handle request here.
https://laravel.com/docs/5.3/routing#parameters-optional-parameters

Pass variable from middleware to view via controller in Laravel 5.2

Hi I am trying to do the following in Laravel 5.2.
Summary: Pass some variables from middleware to view, via controller
Detailed: When a client is logged in, no matter what route they want, we need to check if they have completed all "setup steps" (each step refers to a different route, e.g. one could be company info, another could be product settings, etc). If they have completed all setup steps, then let them proceed to their chosen route, otherwise we redirect to the appropriate "setup steps" route, whichever one they haven't completed yet.
All client controllers run the same middleware, called NonSuperAdmin. I would like to put the checking of "setup steps" in this middleware, and redirect from there as appropriate. If client is redirected to a setup route by this middleware, we need the "incompleteSetupTasks" collection to be passed on to the relevant view, via the appropriate setup steps controller method.
Is this possible? Any help is much appreciated.
In the middleware use session handler
if($condition === true){
$data = [ //your content ];
Session::flash('your_key', $data);
}
next($request);
This data will also be available in your controller and in view
This is how you can access data in controller
public function yourControllerAction($request)
{
$somevariable = Session::get('your_key');
$viewdata = [
'content' => $somevariable
]
return view('yourview', $viewdata);
}
Or directly access the session data in view
//inblade
<p>
Your html content
#foreach(Session::get('your_key' as $data)
//your stuff
#endif
</p>
May be use Laravel Session to store and read values?
You can pass your setup steps to get or post parameters and check in routes with middleware if these parameters are empty:
Route::get('post/{setup1?}/{setup2?}', ['middleware' => 'role:admin', function ($setup1, $setup2) {
if(empty($setup1) and empty($setup2)){
// do smth
} else {
// redirect
}
}]);
Question marks mean, that they are optional parameters. Hope it was helpful.

How to Remove/Register Suffix on Laravel Route?

EDIT: See below for my current problem. The top portion is a previous issue that I've solved but is somewhat related
I need to modify the input values passed to my controller before it actually gets there. I am building a web app that I want to be able to support multiple request input types (JSON and XML initially). I want to be able to catch the input BEFORE it goes to my restful controller, and modify it into an appropriate StdClass object.
I can't, for the life of me, figure out how to intercept and modify that input. Help?
For example, I'd like to be able to have filters like this:
Route::filter('json', function()
{
//modify input here into common PHP object format
});
Route::filter('xml', function()
{
//modify input here into common PHP object format
});
Route::filter('other', function()
{
//modify input here into common PHP object format
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
Route::when('*.xml', 'xml'); //Any route with '.json' appended uses json filter
Route::when('*.other', 'other'); //Any route with '.json' appended uses json filter
Right now I'm simply doing a Input::isJson() check in my controller function, followed by the code below - note that this is a bit of a simplification of my code.
$data = Input::all();
$objs = array();
foreach($data as $key => $content)
{
$objs[$key] = json_decode($content);
}
EDIT: I've actually solved this, but have another issue now. Here's how I solved it:
Route::filter('json', function()
{
$new_input = array();
if (Input::isJson())
{
foreach(Input::all() as $key => $content)
{
//Do any input modification needed here
//Save it in $new_input
}
Input::replace($new_input);
}
else
{
return "Input provided was not JSON";
}
});
Route::when('*.json', 'json'); //Any route with '.json' appended uses json filter
The issue I have now is this: The path that the Router attempts to go to after the filter, contains .json from the input URI. The only option I've seen for solving this is to replace Input::replace($new_input) with
$new_path = str_replace('.json', '', Request::path());
Redirect::to($new_path)->withInput($new_input);
This however leads to 2 issues. Firstly I can't get it to redirect with a POST request - it's always a GET request. Second, the data being passed in is being flashed to the session - I'd rather have it available via the Input class as it would be with Input::replace().
Any suggestions on how to solve this?
I managed to solve the second issue as well - but it involved a lot of extra work and poking around... I'm not sure if it's the best solution, but it allows for suffixing routes similar to how you would prefix them.
Here's the github commit for how I solved it:
https://github.com/pcockwell/AuToDo/commit/dd269e756156f1e316825f4da3bfdd6930bd2e85
In particular, you should be looking at:
app/config/app.php
app/lib/autodo/src/Autodo/Routing/RouteCompiler.php
app/lib/autodo/src/Autodo/Routing/Router.php
app/lib/autodo/src/Autodo/Routing/RoutingServiceProvider.php
app/routes.php
composer.json
After making these modifications, I needed to run composer dumpautoload and php artisan optimize. The rest of those files are just validation for my data models and the result of running those 2 commands.
I didn't split the commit up because I'd been working on it for several hours and just wanted it in.
I'm going to hopefully look to extend the suffix tool to allow an array of suffixes so that any match will proceed. For example,
Route::group(array('suffix' => array('.json', '.xml', 'some_other_url_suffix')), function()
{
// Controller for base API function.
Route::controller('api', 'ApiController');
});
And this would ideally accept any call matching
{base_url}/api/{method}{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?}{suffix}`
Where:
base_url is the domain base url
method is a function defined in ApiController
{/{v1?}/{v2?}/{v3?}/{v4?}/{v5?}?} is a series of up to 5 optional variables as are added when registering a controller with Route::controller()
suffix is one of the values in the suffix array passed to Route::group()
This example in particular should accept all of the following (assuming localhost is the base url, and the methods available are getMethod1($str1 = null, $str2 = null) and postMethod2()):
GET request to localhost/api/method1.json
GET request to localhost/api/method1.xml
GET request to localhost/api/method1some_other_url_suffix
POST request to localhost/api/method2.json
POST request to localhost/api/method2.xml
POST request to localhost/api/method2some_other_url_suffix
GET request to localhost/api/method1/hello/world.json
GET request to localhost/api/method1/hello/world.xml
GET request to localhost/api/method1/hello/worldsome_other_url_suffix
The last three requests would pass $str1 = 'hello' and $str2 = 'world' to getMethod1 as parameters.
EDIT: The changes to allow multiple suffixes was fairly easy. Commit located below (please make sure you get BOTH commit changes to get this working):
https://github.com/pcockwell/AuToDo/commit/864187981a436b60868aa420f7d212aaff1d3dfe
Eventually, I'm also hoping to submit this to the laravel/framework project.

Resources