Laravel single route point to different controller depending on slugs - php

I'm new to laravel and I have searched a lot for an answer to my problem but either it's not applicable or I'm not getting it.
I have a FileMaker solution for a client that handle customers and events. Each customer to my client have their own event websites that is managed via the solution. A cms simply. Each customer get a site with a url like clientsite.com/event.
Each page in the event has a page-type and I would like to address different controllers depending on the type.
In routes.php i have:
Route::group(['middleware' => ['sal', 'menu']], function () {
Route::get('/{event}/{page}', function($event, $page) {
// Query page for page-type and use controller depending on type
});
});
There are many page types (standard text/image, specialized forms etc) and therefor I would like to address different controllers.
Event names are always unique but pages are not.

You could call a controller manually inside the route closure. Though I would suggest doing the validation in a helper file to make the route file clean and readable.
Route::group(['middleware' => ['sal', 'menu']], function () {
Route::get('/{event}/{page}', function($event, $page) {
// you could do something like
$user_type = Auth::user()->user_type;
if($user_type == "organizer")
{
$controller = $app->make('OrganizerController');
return $controller->callAction('controllerFunc', $parameters = array());
}
else
{
$controller = $app->make('ClientController');
return $controller->callAction('controllerFunc', $parameters = array());
}
});
});

An alternative to the route solution could be to handle the logic in the controller itself:
First, update routes.php to something like:
Route::group(['middleware' => ['sal', 'menu']], function () {
Route::get('/{event}/{page}', 'RoutesController#index');
});
Then, in the RoutesController.php file (add to app/Http/Controllers), you can do something similar to:
public function index()
{
$event = Request::segment(1); // get the {event} part of the route
$page = Request::segment(2); // get the {page} part of the route
// get event data from database, e.g.
$event_data = Event::where( 'slug', $event )->first();
// load correct page
switch ( $page ) {
case "people":
return $this->people();
break;
case "anotherPage":
return $this->another_page();
break;
}
}
private function people()
{
// show view
return View::make('event.people');
}
This solution keeps your routes file clean, but also lets you handle the different event and page data, and load different views depending on the page being looked at. Your extra logic would be better in a controller rather than the routes file.
It all depends on where you prefer to code your page / view logic. You can use this approach call functions in the same controller, or external ones.

Related

Is using if else statement to load view based on parameters after controller and action part of url efficient or is there a better way of doing this

I can have the following urls
www.example.com/accounts/
www.example.com/accounts/signup
www.example.com/accounts/signup/validate
www.example.com/accounts/login
for each case, accounts becomes my controller, and index, signup, signup and login becomes my actions (or methods) respectively. I have to render different views based on what my actions are. Here is an example of what my code looks like
index
$url_segments = explode('/', $url);
$controller = !empty($url_segments[0]) ? $url_segments[0] : 'home';
array_shift($url_segments); // removes the controller name from array
$action = isset($url_segments[0]) && !empty($url_segments[0]) ? $url_segments[0] : 'index';
array_shift($url_segments); // removes the action name from array
$controller = ucfirst($controller);
$controller = new $controller($url_segments);
$controller->$action();
controller class
class Accounts{
private $url_segments;
public function __construct() {
$this->url_segments = $url_segments;
}
public function index() {
// index code here
}
public function login() {
// login code here
}
public function signup() {
if (!isset($this->url_segments[0])) {
// url entered was: example.com/signup
} else if (isset($this->url_segments[0]) && $this->url_segments[0] == 'validate') {
// url entered was: example.com/signup/validate
}
}
}
from how my code appeared above, it can be seen that as parameters keep adding after the controller and action part of the url I'll need to keep using conditional statements to run the proper code as in the case of /signup/ and signup/validate. Is this method of using conditional statement to load view based on parameters efficient or is there a better way of doing this.
I would recommend you to make use of a routing system like Symfony Routing. There you could add a new Route for every url and redirect them to your specific controller.
Example Route:
$routes = new RouteCollection();
$routes->add('/accounts_signup', route('POST', "/accounts/signup", 'App\Controller\AccountController:signup'));
return $routes;
This route would call the signup method in the AccountController calss when www.example.com/accounts/signup get called with a post request.
I recommend you to use something like this. Even if this might be a bit complicated for the beginning, after reading (and understanding) the docs this will safe you a lot of time and it will make your code more readable as well.

How to redirect different page from same controller function in laravel 5.2

I want to redirect 2 different page from this controller function along with value.Here is my code. It works but both of time url become same.what shuld I do?
//in routes.php
Route::post('/','mycontroller#check');
// in controller.php
public function check(Request $request)
{
$c_email = $request->email;
$c_pass=$request->pass;
$c_type=$request->select;
$var=DB::select("SELECT * FROM reg where email = '$c_email' and Password = '$c_pass' and type = '$c_type'");
if ($var) {
return view('farmer')->with('user',$var);
// return redirect('farmer')->with('user',$var);
}
else {
$msg="Invalid login";
return view('index')->with('show',$msg);
}
}
If you want to actually redirect u can use the redirect() helper as statet in the official docs https://laravel.com/docs/5.3/redirects
You can also pass data
redirect('/my-route')->with(['user' => $var]);
The passed data can then be accesses through the session helper
$var = session('user')
HOWEVER, it seems like you have major issues in your code. Your password does not seem to be encrypted. Also there's no reason to use plain sql instead of eloquent here.
The route that is shown in the browser is defined in your
Route::post('/','mycontroller#check');
If you just return different views, the route does not change. You need to redirect to other views.
If you redirect to other routes you will ofcourse need to add / define them.
Route::get('/my-route', function() {}); // or post etc.

Route class doesn't working properly

I'm re-writing an application previously written in CodeIgniter framework, my customer want have an independent app and a pure php code. Anyway don't tell me not to reinvent the wheel because I already know that my client is wrong. We come to the problem.
I'm looking for a simple Route class that allow me to call any files from any location. I found this simple and powerfull class, this is the repository.
I've implemented it in my project, copy the route.php file inside the index location and change my .htaccess as the documentation says. Instead of all, this is the structure of my project:
/ PUBLIC_HTML
/ application
/ controllers
/backend.php
/user.php
/ helpers
/ models
/ views
/backend
/backend.php
/calendar.php
/user
/users.php
/panel.php
/ assets
/ files used by frontend...
/ system
/ configuration
/ constant
/ .htaccess
/ index.php
/ route.php
when the applicationi is started from the index.php the configuration file is included for establish the connection with the database. In the same configuration file I've imported the route.php. Now my index.php page is very simple, like this:
// Check if the session is set
if(isset($_SESSION['user_info']['id_roles']))
{
switch($_SESSION['user_info']['id_roles'])
{
case 1: //Admin
$route->add('/application/controllers/backend', 'index');
$route->submit();
break;
case 2: //Provider
$route->add('/application/controllers/backend');
$route->submit();
break;
case 3: //Customer
$route->add('/application/controllers/appointments');
$route->submit();
break;
}
}
else
{
// Session isn't set, so I redirect user to login page
header('Location: application/views/user/login.php');
exit; // stop
}
so if the session is set I redirect the user type to the correct location, against, if isn't set I show the login page. The login page simply valorize the session variable, if the response is success the user is redirected again to the index page.
The problem now is that, for example when the admin is logged (so case 1), the route class doesn't valorize the $uri, a bit example:
public function submit()
{
$uri = isset($_REQUEST['uri']) ? $_REQUEST['uri'] : '/';
$uri = trim($uri, $this->_trim);
$replacementValues = array();
// Iterate on the list of URI
foreach($this->_listUri as $listKey => $listUri)
{
// Looking for a match..
if(preg_match("#^$listUri$#", $uri))
{
// Replace the values
$realUri = explode('/', $uri);
$fakeUri = explode('/', $listUri);
// Get value with .+ with real URI value
foreach($fakeUri as $key => $value)
{
if ($value == '.+')
{
$replacementValues[] = $realUri[$key];
}
}
// Pass array arguments..
call_user_func_array($this->_listCall[$listKey], $replacementValues);
}
}
}
check the full class here.
the $uri variable should be valorized with the current uri of the server but I tried with a var_dump and I get an empty value.Then the match condition is never invoked, and the correct file isn't displayed. I don't know why, I just want to understand why it is not working, I'm probably doing something wrong, someone can help me understand?
Completing the example of the admin redirect, I want to show only what is contained in the backend.php, which should be loaded from the route.
<?php
session_start();
class Backend
{
// Construct of class
public function __construct()
{
}
// Display the main backend page
public function index($appointment_hash = '')
{
$_SESSION['user_info']['hash'] = $appointment_hash;
$_SESSION['user_info']['dest_url'] = SystemConfiguration::$base_url . "backend";
// some content..
}
...
So how you can see, I simply want call the index function of the backend controller when I call ->add() for add the url of the controller to call, and ->submit() to perform the operation.
What am I doing wrong?
UPDATE - Router request task
First I updated the stack of my application.
I think at this point it's best to ask your expert advice on which OpenSource Router allow me to implement this tasks:
1. Import controller
Import all controllers that are contained in my folder called controllers. Once you imported I will simply call the instance of the router, and call up a specific function of the controller loaded. Example:
$router->backend->index();
where index(); It represents the function of controller called backend.
This must be done in my entire application. Also I would make sure that we can bring up the function also via the URL, in particular, if I insert this url:
localhost/application/controllers/backend/index
I can call the same function simply referring url.
2. Requests ajax
 
Delivery My Router must be able to run ajax requests from javascript, especially if I use this code:
$('#login-form').submit(function(event)
{
var postUrl = GlobalVariables.baseUrl + 'user/ajax_check_login';
var postData =
{
'username': $('#username').val(),
'password': $('#password').val()
};
$('.alert').addClass('hidden');
$.post(postUrl, postData, function(response)
{
I want to call the user function ajax_check_login.
contained in the controller user, imagine GlobalVariables.baseUrl, what is... How can we think is the url of the base application that can obviously vary.
Note that my Controller function return a json format.
3. Load view
in my application there is the view, which are saved in .php, but containing html file, an example of view (previously written in CodeIgniter) pul you find here.
I want to be able to call a view and show the new user html markup. I also need to call also more views at the same instant, for example at times I divide the body into:
header, body, footer
To simplify the understanding of what $this refers to in a view, since a view is "loaded" by a controller method, the view is still run in the same scope as that method, meaning $this can have a different context depending on which class loaded it.
For example:
class Controller1 extends CI_Controller {}
In any view file loaded in this example controller, $this refers specifically to the Controller1 class, which can access CI_Controller public and protected properties/methods as well (like the Loader or Input classes, which are assigned to the load and input properties of CI_Controller) since it extends that class.
Controllers are still just plain old PHP classes. If I were to do this:
class Controller1 extends CI_Controller {
$this->foobar = 'Hello';
}
class Controller2 extends CI_Controller {
$this->foobar = 'World';
}
...if we load the same view file in any method of either of these controllers, using $this->foobar in that view file will return a different value.
But this for now it's not important, I just want to be as clear as possible.
I start a bount and lose all my rep, but I really want to get help in this and learn.
You need to look at the index.php provided with the Router as an example. You'll see how to set the routes:
you always have to have 2 arguments: 1. uri, 2. function
according to the example the function has to be not the function name 'index', but a function body function(){...}. Maybe reference would work as well.
Routing IMHO should be not dependant on session (though it could be, but that's not the usual way to do)
instead of $router->backend->index();, I will have a common block of code at the end of the file so you don't have to copy&paste the code many times.
I'll show you with backend in your way, and then with appointments how could you make it general. So you should make your routes something like:
<?php
session_start();
include 'route.php';
$phpClass = false;
$view = false;
$func = false;
$route = new Route();
if(isset($_SESSION['user_info']) && isset($_SESSION['user_info']['id_roles'])) {
$route->add('/application/controllers/backend', function(){
echo 'You are now at backend page, and the role is ';
switch($_SESSION['user_info']['id_roles']) {
case 1: echo 'Admin'; break;
case 2: echo 'Provider'; break;
case 3: echo 'Customer'; break;
}
include 'backend.php';
$backend = new Backend();
$backend->index(/* I don't know what 'hash' could be */);
});
// more general case:
$route->add('/application/controllers/appointments', function(){
// we only set the global $phpClass variable, and the rest is common, see below
global $phpClass, $func;
$phpClass = 'Appointements';
$func = 'index'; // default is index, if it wasn't given on the url
});
$route->add('/application/controllers/appointments/add', function(){
// we only set the global $phpClass variable, and the rest is common, see below
global $phpClass, $func;
$phpClass = 'Appointements';
$func = 'add';
});
$route->add('/application/controllers/appointments/delete', function(){
// we only set the global $phpClass variable, and the rest is common, see below
global $phpClass, $func;
$phpClass = 'Appointements';
$func = 'delete';
});
$route->add('/application/controllers/foo', function(){
global $phpClass;
$phpClass = 'Foo';
});
$route->add('/application/controllers/bar', function(){
global $phpClass;
$phpClass = 'Bar';
});
$route->add('/application/views/bar', function(){
global $phpClass, $view;
$phpClass = 'View';
$func = 'show';
$view = 'bar.php';
});
$route->submit();
} else {
// Session isn't set, so I redirect user to login page
header('Location: /application/views/user/login.php');
exit; // stop
}
if ($phpClass === false || $func === false) {
die("You have to have both controller and function un the url");
}
// if we got here it means we're in the common case
// include the necessary controller. If you want you can
// include all of them at the top of the php and remove this line
include 'application/controllers/' . strtolower($phpClass) . '.php';
$controller = new $phpClass();
// this is instead of `$router->backend->index();`:
$controller->$func(/*$hash*/);
// I don't know what '$hash' could be, maybe javascript could send it via ajax
?>
controllers/view.php:
class View {
public function show() {
global $view;
include 'application/views/' . $view;
}
// here you'll need to have all the things that any of
// your views access as $this->bar :
$config = new stdClass(...);
$array = array();
function get_lang() {global $lang; return $lang;}
//...
}
Example of json response in controllers/user.php:
class User {
public function logged_in() {
$username = isset($_SESSION) && isset($_SESSION['username']) ? $_SESSION['username'] : false;
$response = array(
'success' => $username !== false ? 'OK' : 'ERROR',
'username' => $username
);
echo json_encode($response);
}
}

Is a POST controller suitable in a php mvc?

I am creating a custom MVC style framework from scratch and am at the point where I need to implement the code to control what happens on POST.
At the moment I have a main index.php which acts as a controller and passes data to other controllers such as:
profilecontroller.class.php
forumcontroller.class.php
At the moment I see two options as to where the POST controllers can go ..
First Approach
Firstly for site wide posts such as login that can occur on any page I would use something like this in the very first index.php to redirect all POST to a specific POST controller that then sends the data to a model to be processed:
if($_POST)
//post controller, works on specific form id's
Alternate Approach
The other option I see would be to build the POST identifier into the model construction sections but I don't think this would be very manageable/wise as they'd always be checked and resulting in more loaded code?
Are there any good/simple examples out there?
I'm creating my mvc to be as light as possible so that's my reason for going from scratch.
In a RESTful setup, you would normally have a controller for an object, say news, and then actions such as add, edit, delete etc.
Within your actions, you should then assert what HTTP method should be used to access the method, if one should be. For example:
<?php
class NewsController extends AbstractController {
public function save() {
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
header('HTTP/1.1 405 Method Not Allowed');
die('Please use POST.');
}
// carry on knowing we're working with a POST request
}
}
Creating a separate controller for POST requests would, as you say, quickly becoming unruly and unmanageable.
If you're looking for a way of handling requests for different HTTP methods within different controller actions, then maybe check out ToroPHP. It's a lightweight (single file) router, where you map a request to a class that's referred to as a handler, and then that handler has methods for different HTTP methods. A quick example:
<?php
require 'lib/torophp/toro.php';
require 'classes/handlers/HomeHandler.php';
$toro = new ToroApplication(array(
array('/', 'HomeHandler')
));
$toro->serve();
And then your HomeHandler would look as follows:
<?php
class HomeHandler {
public function get() {
echo 'Hello, world!';
}
public function post() {
echo 'Try performing a GET request for the home page, buddy.';
}
// and so on...
}
Hope that helps.
This is my default Controller :
<?php
Class Controller_Home{
public $Registery = null;
final public function __construct($Registery){ $this->Registery = $Registery; }
final public function Init($Method=null){
# Quelle action on fait ?
if($Method){
$Split = explode('_', $Method);
$MethodName = 'Action';
foreach($Split as $Splitted){
$MethodName.= '_'.ucfirst($Splitted);
}
if(method_exists($this, $MethodName)){
$this->$MethodName();
} else {
echo '404';
die;
}
} else {
$this->Action_Default();
}
}
final public function Action_Default(){
$this->Registery->Import('Library.Account');
var_dump($this->Registery->Account);
echo 'Default Home';
}
}
As you can see, once you are in Action_Default, you can do whatever you want based on $_GET, $_POST, whatever you want ...
So with this code :
website.com/home/bob/ will use function Action_Bob inside the controller Home (Home::Action_Bob) ... if you see $_POST just put inside Action_Bob this
public function Action_Bob(){
if($_POST){
$this->Action_Bob_Post();
}
// continue
}

Laravel 5.2, Load a view based on user information

This is a fresh installation of Laravel 5.2, the only thing I did was to add a new column to the table users this new column is call roles which is just integers...
What I'm trying to do is to load a controller/view base on the information of this column...
Say if the column roles has a value of 1 then load the view X
in my routes file I have this
Route::group(['middleware' => ['web']], function () {
Route::auth();
if(Auth::user()->roles == '1') {
Route::get('/admin', 'AdminController#index');
Route::post('/admin', 'AdminController#save');
Route::get('/admin/{datas}', 'AdminController#datas');
Route::get('/admin/list', 'AdminController#list');
Route::get('/admin/list/{details}', 'AdminController#details');
} else {
Route::get('/login', 'UsersController#login');
}
if I use this Auth::user()->roles == '1' inside a view it "works" but is not what I want and I really don't want to install 3rd packages for user control, I just want something very simple... so how can I accomplish this?...
Based on what Matt said(I didn't get it at first, I'm new to laravel so bear with me), this is what I did...
Install a fresh laravel...
then run this php artisan make:auth, it will install everything you need for users to register/login/reset...
then open your AuthController.php change this protected $redirectTo = '/home' for whatever you want, in my case I called delegate $redirectTo = '/delegate'
then on your routers.php file put something like this
Route::group(['middleware' => ['web']], function () {
Route::auth();
Route::get('/delegate', 'DelegateController#index');
});
You don't actually need a view for this route, what you need is the controller...
On this controller DelegateController.php will put something like this
namespace App\Http\Controllers;
use App\Http\Requests;
use Auth;
use Illuminate\Http\Request;
// use App\Http\Controllers\Controller;
class AdminController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
//
public function index() {
// TODO Gets Data...
$datos = ['Nombre', 'Otro Nombre', 'Otro mas'];
// Return Data to tyhe view...
if(Auth::user()->roles == '11') {
return View('admin.home', compact('datos'));
} else {
return View('/welcome');
}
}
}
And thats how you get different views based on users information... at least is working for me..
------------Update
After I play a little bit with this, I find out that that even when you load the correct view for admin / user / customer / providers...etc the url/path is not correct here is why:
with the code above you get foo.com/login when user loads the Delegation Controller which serves the correct view but the url stays as foo.com/delegate if the user is an admin we want something like foo.com/admin not /delegate and even if you change it manually from /delegate to /admin it still work, but here is the problem because if the user is not an admin it will still shows the admin panel and we don't want that... to fix that I had to change my delegation controller... instead of loading a view I have to redirect the user to a correct path...
public function index() {
if(Auth::user()->roles == '10') {
return redirect()->route('admin');
} else {
return redirect()->route('/');
}
}
this isthe same code as before but instead of loading a view I redirect the user, in order for this to work properly in your routes file you have to declare each the name of each path as follow
Route::group(['middleware' => ['web']], function () {
Route::auth();
Route::get('delegate', 'DelegateController#index');
// Add your route
// Route::get('admin', 'AdminController#home');
Route::get('admin', ['as'=>'admin', 'uses'=>'AdminController#home']);
});
That way you can redirect your user to any part of your site by calling the names route return redirect()->route('/myprofile') ...etc
Now that this is working we need to do one last check as to what user is loading what, to do that is very simple on each of your view controllers you should have something like this...
class AdminController extends Controller
{
public function __construct()
{
$this->middleware('auth');
// gets the disco bouncer working...
if(Auth::user()->roles != '10') {
Auth::logout();
}
}
//
public function home() {
// TODO Gets Data...
$datos = ['Nombre', 'Otro Nombre', 'Otro mas'];
// TODO build a model for the actual data...
// Return Data to the view...
return View('admin.home', compact('datos'));
}
}
As you can see we can use this on all Controllers and skip the DelegationController but then you going to have to do a menu for each user role on a single app.blade master view which will look a lot more dirty...
If you ask me, yes I'm having fun learning Laravel!

Categories