3

I have followed a youtube playlist to build a simple MVC framework based on PHP, here is a link to the playlist I have followed.

and here is an image of my application structure enter image description here

I have connected the application to a MySql database, everything is working fine, but now I am trying to do friendly URLs.

Currently, my URLs look like the following:

mywebsite.com/home/listings/

this is fine as this link is for a static page, but I want the same for dynamic URLs, for example:

Current URL: mywebsite.com/home/listings/apart?id=10

to URL: mywebsite.com/home/listings/apart/id/10

I have tried a lot of methods in htaccss but the data is not pulled from the database once the URL is re-written and I get only an empty page.

current .htaccess code (the one that is located in the public folder):

Options -MultiViews
RewriteEngine On

RewriteBase /public

RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f

RewriteRule ^(.+)$ index.php?url=$1 [QSA,L]

I have tried a lot of methods and rules but non have worked.

I am not sure if the details I provided are clear enough, I am little confused as I combined a lot of tutorials together to create this app.

App.php code:

<?php
  class App{
    protected $controller = 'home';
    protected $method = 'index';
    protected $params = [];
    public function __construct(){
      $url = $this->parseUrl();
        if(file_exists('../app/controllers/' . $url[0] . '.php')){
          $this->controller = $url[0];
          unset($url[0]);
        }
        require_once '../app/controllers/' .$this->controller. '.php';
        $this->controller = new $this->controller;

        if(isset($url[1])){
          if(method_exists($this->controller, $url[1])){
            $this->method = $url[1];
            unset($url[1]);
          }
        }
        $this->params = $url ? array_values($url) : [];
        call_user_func_array([$this->controller, $this->method], $this->params);
    }

    public function parseUrl(){
      if(isset($_GET['url'])){
        return $url = explode('/', filter_var(rtrim($_GET['url'], '/'), FILTER_SANITIZE_URL));
        echo $url;
      }
    }
  }
 ?>

controller.php code:

<?php
  class Controller{
    public function model($model){
      require_once '../app/models/' . $model . '.php';
      return new $model();
    }
    public function view($view, $data = []){
      require_once '../app/views/' . $view . '.php';
    }
  }
 ?>

controllers code:

<?php
  class home extends Controller{
    public function index(){
      $this->view('home/index');
    }
    public function listings(){
      $this->view('home/listings');
    }
    public function property(){
      $this->view('home/property');
    }
  }
 ?>

The project is online, I can give full access if someone interested in helping me solve this issue.

7
  • can you post the code of core/Controller.php Presuming that's got the bit which parses $_GET['url'], btw no one want to sit through a youtube series looking for your issue, please post it here. Commented Sep 28, 2017 at 21:53
  • @LawrenceCherone thank you for your interest in my issue, I just provided the youtube link to give a clear idea about the tutorial I have followed, but of course, I don't want anyone to follow up with it to solve my issue. anyway I have included the controller code, please let me know if there is any other code that can help solve the problem. Commented Sep 28, 2017 at 22:03
  • Ok in the App code, where it returns into $url you should put that inside $this->params like $this->params['params'], then you will be able to access the proceeding URL path from your controllers method. Can't tell which but it will be in the methodName($somthing)` in your controller file. Post a controllers mmetods code if you need further help Commented Sep 28, 2017 at 22:15
  • Actually second look, I see its already being passed as $this->params so post the code of one of your controllers methods Commented Sep 28, 2017 at 22:18
  • Done, I have included the code Commented Sep 28, 2017 at 22:42

1 Answer 1

1

Controller methods need args. App call needs specific params.

In app.php's call_user_func_array() you're already trying to pass arguments to the Controller method being called. You just need the methods to have arguments.

Please be aware that you'll need some validation on your args, as anyone can put anything there.

The absolute simplest form of an answer I can give:

/app/controllers/home.php

public function listings($type = '', $field = null, $value = null){
    $viewParams = [];

    // build model (much of this should be in controller.php)
    // only allow known types
    if (in_array($type, ['apartment','house']) {
        $model = $this->model($type);

        // again, only certain fields (this should be handled in model.php)
        if (in_array($field, ['id','allowedField']) {

            // this is where things can get REALLY dicey. 
            // you'll need to sanitize the value, AND make sure the data-type is compatible with the field
            $modelData = $model->findAndLoadData([$field => $value]);
            $viewParams['type'] = $type;
            $viewParams[$type] = $modelData;
        }
    }

    $this->view('home/listings', $viewParams);
}

Keep in mind the following caveats:

  • There are MANY ways to structure this, and the logic here can be in app, base controller, or the models.
  • Sanitize $value, or build your models so it doesn't matter.
  • You still have to find a way to use those params in the view.
Sign up to request clarification or add additional context in comments.

7 Comments

I have included the App.php code, please let me know if you need any other code that can help solve the problem.
@AhmadTahhan have a look.
Thanks, but I have a lot of questions regarding your answer as this is my first PHP project that is based on MVC and OOP, what do you mean by building a model in the controller.php, do you mean to build the findAndLoadData method, Also, what do you mean by only allowed fields, do you mean fields that exist in the MySQL database.
I did the following and it worked, I don't know if this is a valid way, public function property($params){ $this->view('home/property', $_GET['id'] = $params); }
@Ahmad, by "buiding a model", I mean collecting data from your db, and turning into an object in PHP. These models (M in MVC) should be clearly defined classes, and the only way the rest of your application interacts with the DB. Code to build these models should either be part of your core (in app.php), or in your base Controller class.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.