I'm looking for a fix to allow a redirect in a sub-function call, instead of in a controller
I've created the following function & call and it works, with the redirect in the controller instead of my sub function call.
Here is my call to the function checkAccess():
$access = new \App\Library\Access;
if($access->checkAccess($accessList, 'admin-dashboard', 'r')){
return view('portal.admin.dashboard');
}else{
return redirect('/');
}
Here is my function:
public function checkAccess($accessList, $name, $permission){
return array_filter($accessList, function($element) use($name, $permission){
if($element->name == $name && $element->permission == $permission){
return true;
}else{
return false;
}
});
}
I have tried replacing the return false; with the redirect and this does not work. It basically just returns true.
I'm looking for a fix to allow a redirect in a sub-function call, instead of in a controller
Don't. Your access-checking service should have zero knowledge of the view layer (controllers, views, redirects, etc.). If you've ever heard of concepts such as separation of concerns and the single responsibility principle, that type of blending is exactly what these concepts encourage you to evaluate and separate properly.
Your Access class is meant to check for access levels, permissions, etc. It should not be meant to generate responses based on those things. That's the controller's job.
Your first code example is perfectly fine, and is what I'd recommend you stick with.
If I understand your issue, you want something like this
public function checkAccess($accessList, $element, $permission){
if (is_array($accessList)) {
foreach ($accessList as $access) {
if ($access->element == $element && $access->permission == $permission) {
return view('portal.admin.dashboard');
}
}
}
return redirect('/');
}
and then, you should return the result
$access = new \App\Library\Access;
return $access->checkAccess($accessList, 'admin-dashboard', 'r');
Concerning the better way of checking if an object list has parameters, maybe you find useful the in_array function of php.
Related
I'm trying to make things more simple in my Laravel application. Therefore I'm wondering how's it possible to NOT redirect the Client if one of my function returns true and how to redirect if it is a string (not true).
So let's say I have a function like this:
public function returnText() {
$r = rand(1,100);
if ($r > 50)
{
$redir = true;
}
else
{
$redir = 'http://google.com';
}
return $redir;
}
What I want within my Laravel's controller's function is to redirect the user if the result is an URL and don't redirect if it's simply 'true' (or anything basically it doesn't matter if I return true or something else).
Now I can obviously do that with a few lines but I'd like to optimize it only to take 1 max 2 lines.
public function redi() {
return redirect(CustomFunction::returnText());
}
I've tried this approach but it obviously throws some error, because it can't understand 'true'.
Any ideas on how to achieve this with the least lines of code?
P.S.: using Laravel 5.5
redirect() function requires uri to redirect to and true boolean value is invalid, hence the error.
So, you can do something like this in your function:
public function redi() {
$redirectUrl = CustomFunction::returnText();
if (!is_bool($redirectUrl)) {
return redirect($redirectUrl);
}
return;
}
i.e. only redirect if it gives you anything but a boolean value.
I used laravel's authorization in my code and defined the before method in my service provider as shown in the documentation:
public function before($user, $ability)
{
if ($user->email == 'super#mail.com') {
return true;
}
}
Sometimes I need to know if the checks were intercepted. So, instead of checking the mail (or any other condition for superuser) in different places, I want to check if this intercepting method is used. I mean instead of using this (if email is equal...) condition in different places again and again. I want to set this super admin condition only once (in the service provider) and then check it when needed. Something like:
\Gate::isIntercepted
Instead of simply returning true, you can return an authorization response:
public function before($user, $ability)
{
if ($user->email == 'super#mail.com') {
return $this->allow('superadmin');
}
}
You'll get the response later on if you use authorize:
public function update(Post $post)
{
$response = $this->authorize($post);
if ($reponse->message() == 'superadmin') {
// do something
}
}
Part of my application is a multi-stage checkout process; during the latter pages of this I first run a sanity check on each request to verify the user actually has some items in their basket: if not they're sent back to the beginning.
I have a controller function like this which is called from multiple routes for DRY purposes.
private function checkBasketFull($request)
{
if (self::isBasketEmpty($request)) {
return redirect('/')->with('status', config('app.empty_basket_message'));
}
}
When I call it, I can't just do:
self::checkBasketFull($request);
because without a return the redirect doesn't fire, only the session data is sent.
And I can't do:
return self::checkBasketFull($request);
because that will give an error if there's no redirect or abort the method if checkBasketFull returns anything else.
My current (working) code is:
$check = self::checkBasketFull($request);
if ($check) {
return $check;
}
Is there an alternative way of writing this on a single line, or modifying the checkBasketFull function, so the redirect will occur if the basket is empty but execution will continue as normal if it isn't?
Either use this:
if ($redirect = self::checkBasketFull($request)) return $redirect;
Or throw an error and catch it in the global error handler.
However, instead of returning and checking that for a redirect like that, I'd much rather keep it as two completely separate methods:
public function someRoute(Request $request)
{
if ($this->isBasketEmpty($request)) return $this->redirectBasketEmpty();
// Continue processing this request...
}
protected function isBasketEmpty(request)
{
// run your login here...
}
protected function redirectBasketEmpty()
{
return redirect('/')->with('status', config('app.empty_basket_message'));
}
Feels cleaner to me.
I'm trying to convert my PHP app into more of an MVC app. I don't have much experience with MVC and I don't fully understand some of/all of the concepts or how to do it with PHP, so I need some help understanding where a particular function goes.
This function returns some HTML depending on if the user is logged in.
public function buildLoggedInMessage() {
if ($this->User->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
My initial thought was to place this function in my "controller" because it asks the User model if they are logged in (which checks the database record), however it "builds" some HTML, so maybe it should be in the view. Should I move it?
I will eventually move the HTML from the function into a template, so ignore the inline HTML.
Would the function be more suitable in the view if it was like this:
public function buildLoggedInMessage() {
if ($this->Controller->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
and the controller asks the model if the user is logged in?
Thanks.
I think view should not contain any business logic. Views should focus on presenting stuff, so your second solution is bad practice.
More than that, since views focus on the presentation and models handle most of the business logic, controllers should do only the necessary things to link views and models, which means fetch data from model and just insert the data into the view.
so this line of code make no sense because it means you implement business logic in controller:
$this->Controller->isLoggedIn()
Now let's see your first solution.
public function buildLoggedInMessage() {
if ($this->User->isLoggedIn()) {
return ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
return ' Login';
}
}
This function 'return' htmls rather than 'echo' htmls. So who is calling this function? and who will 'echo' the string from this function? I would say this is not a complete controller.
In modern web MVC, there's always some kind of 'router' handle the http requests and execute some instructions related to that. Since you wanna implement MVC pattern, you need to implement that 'router' first.
For example, you can create a 'Member' class which has a 'check' method to achieve the functionality you want.
class Member{
public function check() {
if ($this->User->isLoggedIn()) {
echo ' You are logged in as <strong>'.$this->User->getUsername().'</strong> (logout)';
} else {
echo ' Login';
}
}
}
And you need to implement the router class to handle http requests like 'http://myweb.com/member/check'.
The router code would be something like this:
$url_segments = explode('/', $_SERVER['REQUEST_URI']);
if (count($url_segments) == 4){
$controller_name = $url_segments[2];
$method_name = $url_segments[3];
}
else if (count($url_segments) == 3){
$controller_name = $url_segments[2];
$method_name = $this->default_method;
}
else if (count($url_segments) == 2){
$controller_name = $this->default_controller;
$method_name = $this->default_method;
}
$this->current_controller = $controller_name;
$this->current_method = $method_name;
require BASEPATH . '/controller/' . $controller_name . '.php';
$class_name = ucfirst($controller_name);
$controller = new $class_name($method_name);
call_user_func( array( $controller, $method_name ) );
Create a MVC framework is not an easy work.
I create a simple MVC framework for educational purpose.
https://github.com/howtomakeaturn/PigFramework
Check the index.php file, and you will know what I mean router and controller.
I don't think that the point of MVC is to put HTML in a controller, if I were you I'd send some data back and make an if else statement in my view based on the send data. To make good use of an MVC you first need to understand what it is or does, so I'd recommend searching for a tutorial.
put this function in the controller from where you are calling a login function after if a user authenticated then it will set the session or flash data i.e $this->session->set_flashdata('success', 'you are loged in as $username');
else
redirect('login');
In a Laravel controller I have a couple of methods that all begin by fetching a database record, then after checking if data has been found either continue by rendering a view, or, in case of no data, go to a 404 page.
Here's an example:
<?php
function get_show_user($id)
{
$user = static::get_user($user_id);
if (!$user) {
return Response::error('404', static::$some_common_error404_message);
}
return View::make('users.show_readonly_user_data')->with('user', $user);
}
function get_edit_user($id)
{
$user = static::get_user($user_id);
if (!$user) {
return Response::error('404', static::$some_common_error404_message);
}
return View::make('users.display_edit_user_form')->with('user', $user);
}
I'm repeating the entire if (!$user) statement in these methods, even if they all do the same thing.
I'd rather like to do something like this:
function get_show_user($id)
{
$user = Users::find($id);
static::go404_if_null($user);
return View::make('users.show_readonly_user_data')->with('user', $user);
}
function get_edit_user($id)
{
$user = Users::find($id);
static::go404_if_null($user);
return View::make('users.display_edit_user_form')->with('user', $user);
}
What would be the best way to implement such a DRY feature?
Obviously a simple return Response::error('404') would not work in the common existence checker method, since it would only return from that method.
It seems that an Event::fire('404') is not ideal either since it does not terminate the method it has been triggered in.
Perhaps using an exception would be required here, but I'm unsure about this, or how it should be done in Laravel. Where should I catch a 404 Exception of a controller?
I think the best way to approach this would be a before filter on your controller.
public static $require_user = array(
'edit_user',
'show_user',
);
public function before()
{
$route = Request::route();
if ( in_array( $route->controller_action, static::$require_user ) )
{
$this->user = User::find( $route->parameters[0] );
if ( is_null($this->user) ) return Response::error('404');
}
}
Before filters get called after your controller is constructed but before the method is called. If a before filter returns anything other than null, the method is not called and thus execution is stopped.
Here we obtain the current route being executed so we can check which method is going to be called against our array $require_user. This lets us use methods that don't require a user id, such as login.
Then we retrieve the user instance, getting the id from what would have been passed to the method. You should probably add more error handling here.
Lastly, we check if the user returned was null, meaning not found. If that is the case we return a 404 response, stopping execution of the method.
I hope this helps!