Laravel dynamic return from controller? - dynamic

I need to return a different view from a controller depending on the route that is requested.
For example: in my application I have clients, devices and campaigns. All have CRUD's created, but in some cases I want to do something like "view clients, delete his campaign and returning to the clients view" but my campaignsController#delete returns to campaigns by default.
The idea is not rewrite the same controller only changing the route of returning, does Laravel have something to help with this?
Thank you

Laravel will not control the whole flow of your application. If you have a campaign delete router:
Route::delete('campaign/{id}');
and it returns to campaigns
class CampaignController extends Controller {
public function delete($id)
{
$c = Campaign::find($id);
$c->delete();
return Redirect::route('campaigns');
}
}
You will have to trick your route to make it go to wherever you need to, there should be dozens of ways of doing that, this is a very simple one:
Route::delete('campaign/{id}/{returnRoute?}');
class CampaignController extends Controller {
public function delete($id, $returnRoute = null)
{
$returnRoute = $returnRoute ?: 'campaigns';
$c = Campaign::find($id);
$c->delete();
return Redirect::route($returnRoute);
}
}
And create the links in those pages by using the return route option:
link_to_route('campaign.delete', 'Delete Campaign', ['id' => $id, 'returnRoute' => 'clients'])

Related

Appending hash/fragment to RedirectResult results in cumbersome code

The code works but is silly.
When the View is returned to the user the page scrolls to the companyId anchor.
Silly is that I have to expose another public action with another route (without 'terms')
I want to redirect to /terms/companyId but then I get an ambigiousAction exception that this action with same routes already exists...
How to solve that dilemma if possible not change the first route?
[HttpGet("~/terms/{companyId}")]
public IActionResult Home(string companyId})
{
string url = Url.Action(nameof(HomeForRedirect), new { companyId}) + "#conditions";
return new RedirectResult(url);
}
[HttpGet("{companyId}")]
public IActionResult HomeForRedirect(string companyId)
{
Viewbag.CompanyId = companyId;
return View(nameof(Home));
}
If I'm understanding your code, you essentially want the URL /terms/{companyId} to redirect to /{controller}/{companyId}#conditions? The easiest path would be to attach both routes to the same action and do the redirect in a conditional. Something like:
[HttpGet("{companyId}", Order = 1)]
[HttpGet("~/terms/{companyId}", Order = 2)]
public IActionResult Home(string companyId)
{
if (Context.Request.Path.StartsWith("/terms"))
{
var url = Url.Action(nameof(Home), new { companyId }) + "#conditions";
return Redirect(url);
}
ViewBag.CompanyId = companyId;
return View();
}
An even better method would be to simply do the redirect directly in IIS. There's a not insignificant amount of processing that needs to occur to handle a request in ASP.NET Core machinery, and it's totally wasted effort simply to redirect. Use the URL Rewrite module in IIS to set up your redirect for this URL, and then your application doesn't have to worry about it at all. You just have your normal run-of-the-mill Home action that returns a view, and everything will just work.
A few other notes since it seems like you're new to this:
It's better to use the Route attribute rather than the more specific HttpGet etc. The default is GET.
Return the controller methods like Redirect rather than instances of IActionResult (i.e. new RedirectResult(...)).
The default is to return a view the same name as the action. So, assuming your action is Home, you can just do return View(), rather than return View(nameof(Home)).

Voyager - laravel admin panel

My question is related to controller in Voyager admin panel. For example I created a table with migration . It's name was "groups" and then I created BREAD and added it to menu in Voyager.
I created a folder that it's name is "groups" in \resources\views\vendor\voyager andthen I created two file to override the view.
But I do not know where the controller is . I created controller with php artisan make:controller GroupsController. I guess this controller is not related to voyager controllers.
I want to change the index or create method and pass some data to views in controller but I do not know where it is.
I created a controller in \vendor\tcg\voyager\src\Http\Controllers that it's name is VoyagerGroupsController.php but when I create class and index method in it , it does not work.
How can I create controller for "groups" and pass the data to the view?
Whenever we create a table in voyager, Voyager calls it datatype. And for all tables / datatypes created by us, Voyager users only one controller VoyagerBreadController.php located at **vendor\tcg\voyager\src\Http\Controllers**.
For example, if I create a table named brands. Laravel will use controller VoyagerBreadController.
But where are the routes which use or point to this controller. Routes are located in file vendor\tcg\voyager\routes\voyager.php. In this file, find the following lines:
try {
foreach (\TCG\Voyager\Models\DataType::all() as $dataTypes) {
Route::resource($dataTypes->slug, $namespacePrefix.'VoyagerBreadController');
}
} catch (\InvalidArgumentException $e) {
throw new \InvalidArgumentException("Custom routes hasn't been configured because: ".$e->getMessage(), 1);
} catch (\Exception $e) {
// do nothing, might just be because table not yet migrated.
}
In my version, these lines are between line No. 29 to 37.
As you can see, above code is fetching all our datatypes and creating a resouce route for our tables / datatypes.
Now, if I want to override this route and create a route to use my own controller for a particular action. For example, if I want to create a route for brands/create url. I can do this by simply adding following line (my route) below above code (i.e. after line 37):
Route::get('brands/create', function(){return 'abc';})->name('brands.create');
or you can do the same by adding following line in routes\web.php after Voyager::routes();
Route::get('brands/create', function(){return 'abc';})->name(**'voyager.brands.create'**);
Because it's now it's using your App controller not a Voyager controller so you have to override your full controller
like
In config/voyager.php add
'controllers' => [
'namespace' => 'App\\Http\\Controllers',
],
Create new controller like MyBreadController.php into App/controller
<?php
namespace App\Http\Controllers;
class MyBreadController extends \TCG\Voyager\Http\Controllers\Controller
{
//code here
}
app/Providers/AppServiceProvider.php
use TCG\Voyager\Http\Controllers\VoyagerBreadController;
use App\Http\Controllers\MyBreadController;
public function register()
{
$this->app->bind(VoyagerBreadController::class, MyBreadController::class);
//
}
I added Route::get('groups', 'GroupsController#index') as you said in routes/web.php
like this
Route::group(['prefix' => 'admin'], function () {
Voyager::routes();
Route::get('groups', 'GroupsController#index');
});
and added these lines in index method
public function index(Request $request){
// GET THE SLUG, ex. 'posts', 'pages', etc.
$slug = $this->getSlug($request);
// GET THE DataType based on the slug
$dataType = DataType::where('slug', '=', $slug)->first();
// Check permission
Voyager::can('browse_'.$dataType->name);
// Next Get the actual content from the MODEL that corresponds to the slug DataType
$dataTypeContent = (strlen($dataType->model_name) != 0)
? app($dataType->model_name)->latest()->get()
: DB::table($dataType->name)->get(); // If Model doest exist, get data from table name
$view = 'voyager::bread.browse';
if (view()->exists("voyager::$slug.browse")) {
$view = "voyager::$slug.browse";
}
return view($view, compact('dataType', 'dataTypeContent'));
}
But getSlug method does not work. This error will be shown
ErrorException in GroupsController.php line 23:
Trying to get property of non-object
I guess after overriding Controlles getSlug() does not work and I have to set the slug manually
$slug = 'groups';

LARAVEL 5: Need to keep query string after auth redirects

I have a link I am sending via email. For example, www.swings.com/worker?id=3382&tok=jfli3uf
In this case I want the person to click the link, get sent to the login page(which it does) and then be directed to a controller method WITH the $id and $tok variables. I can't get that part to work. Any ideas? I am only using the RedirectIfAuthenticated class and this is what it looks like:
public function handle($request, Closure $next)
{
$user = $request->user();
if ($this->auth->check()) {
if($user && $user->hasRole('worker'))
{
return redirect('worker');
}
return redirect('home');
}
return $next($request);
}
hasRole is a method I created in the User model that checks the role of the logged in user
You can flash data to the session when redirecting by chaining the with() method:
// in your handle() method:
return redirect('home')->with($request->only('id', 'tok'));
// then in home controller method:
$id = session('id');
$tok = session('tok');
AFTER SOME HOURS I WAS ABLE TO HAVE A SOLUTION:
ReturnIfAuthenticated wasn't changed. I just added the following within my controller that this link should go to:
for instance, the route would be:
Route::get('worker', 'WorkerController#methodINeed');
Within this method:
public function methodINeed() {
$id = Input::get('id');
$tok = Input::get('tok');
// Do what I need this variables to do
}
What I didn't understand and what could not be properly understood is that the auth controller in Laravel 5 is triggered when a user is a guest it will still redirect to the actual method with all its original data once auth is successful. Hope this is helpful.

Is it possible to render View without create Action in ASP.NET MVC?

Is it possible to get/render View without creating Action in Controller? I have many Views where I dont need pass any model or viewbag variables and I thing, its useless to create only empty Actions with names of my Views.
You could create a custom route, and handle it in a generic controller:
In your RouteConfig.cs:
routes.MapRoute(
"GenericRoute", // Route name
"Generic/{viewName}", // URL with parameters
new { controller = "Generic", action = "RenderView", }
);
And then implement a controller like this
public GenericContoller : ...
{
public ActionResult RenderView(string viewName)
{
// depending on where you store your routes perhaps you need
// to use the controller name to choose the rigth view
return View(viewName);
}
}
Then when a url like this is requested:
http://..../Generic/ViewName
The View, with the provided name will be rendered.
Of course, you can make variations of this idea to adapt it to your case. For example:
routes.MapRoute(
"GenericRoute", // Route name
"{controller}/{viewName}", // URL with parameters
new { action = "RenderView", }
);
In this case, all your controllers need to implement a RenderView, and the url is http://.../ControllerName/ViewName.
In my opinion it's not possible, the least you can create is
public ActionResult yourView()
{
return View();
}
If these views are partial views that are part of a view that corresponds to an action, you can use #Html.Partial in your main view to render the partial without an action.
For example:
#Html.Partial("MyPartialName")

How do I make a construct to have beforeAuth only apply to certain views/functions in Laravel 4

I have a resource in Laravel I have called artists with an ArtistsController. I would like to add filters to some of the pages, but not all. I know I can add a filter to all of the functions/views in the resource controller like so:
public function __construct()
{
$this->beforeFilter('auth', array('except' => array()));
}
How do I add the beforeAuth filter to only a certain view/function? I would like a user to be logged in in order to go the "index" view, but I would like a user to be able to go to the "show" pages without necessarily being logged in:
public function index()
{
$artists = Artist::all();
return View::make('artists.index', compact('artists'))
->with('artists', Artist::all())
->with('artists_new', Artist::artists_new());
}
public function show($id)
{
$artist = Artist::find($id);
return View::make('artists.show', compact('artist'))
->with('fans', Fan::all());
}
Is there a way to do this? Thank you.
Not sure if this helps but you could use the only key instead of the except (if I understand your question correctly).
$this->beforeFilter('auth', array('only' => array('login', 'foo', 'bar')));
Although that would still go in the constructor.