Route class doesn't working properly
Asked Answered
K

1

8

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.

Karrykarst answered 31/1, 2016 at 9:58 Comment(8)
I was not happy with the end result of our session. I decided to have a look around for some routers that will call methods on controllers directly. I found a couple: Routing lets you create your own url paths, based on the path you can load a closure or a controller. Also: PHP Router class - calls methods on controllers. I hope you will find them useful?Vashtivashtia
@Gavriel There are some points that I need to clarify on the class of router, I hope that we can discuss it together so as to help other members of StackOverflow. I'm in chat now.Karrykarst
Since when were frameworks not 'pure php code' ?Arundel
@Vincent There is a chat session for evaluate the best solution of the problemKarrykarst
Thanks for that - it looks interesting... will check in later.Vashtivashtia
@Karrykarst as i understood your main problem is that during request to your domain.com with admin logged in state your $_REQUEST['uri'] is empty and you don't see any content yes , instead you want to have loaded case 1: files loaded yes ?Bagley
when you say pure and independent php, how 'pure' and how much 'independent' are you required to make it? I am quite confused as you are using a bitbucket code with GPL license when better and more solutions exist with MIT/BSD license.Adiaphorous
@Armen, yes. The uri is different against the uri passed as parameter in add methodKarrykarst
T
3

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);
    }
}
Transcendental answered 2/2, 2016 at 10:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.