1
\$\begingroup\$

I'm redisigning my old Feed Reader APP with the MVC architecture, to understand the OOP better, currently there is just registration functionallity implemented, ...urrently workiing on the session control for the login system.

Im curious how this will look in the end, but currently it seems like its easier to extend and you know exactly where to look when there are any errors. I am also trying error catching with try catch blocks, which also works nice and helps to make the code look cleaner.

My biggest problem in this project till now was on where exactly place the function, i read many MVC examples on some pages like GitHUb and also StackEx. which resulted in the following implementation of functions.

To the code: I'm using TWIG as a templating system, wanted to use a framework that works "out of the box" without big installation processes.

There is a routing script called application.php which gets loaded on the index.php and routes requests by the URL. This url gets decunstructed and analyzed by the constructor of it.

The next step is the controller, the controller creates the Model Object. And the proper extension of the controller develops the view by creating a TWIG object which allows to print the template (For ecample UserClass->register(); prints the registration site); UserClass->login(): prints the login page and so forth).

After that everything is done. The registration is handled by an AJAX "GET" request to the proper controller (in this case: UserController.php) which has the registration function.

This is the application.php which routes:

<?php
class Application
{
    /** @var null The controller */
    private $url_controller = null;
    /** @var null The method (of the above controller), often also named "action" */
    private $url_action = null;
    /** @var array URL parameters */
    private $url_params = array();
    /**
     * "Start" the application:
     * Analyze the URL elements and calls the according controller/method or the fallback
     */
    public function __construct()
    {
        require_once 'vendor/autoload.php';
        Twig_Autoloader::register();
        $loader = new Twig_Loader_Filesystem('views');
        $twig = new Twig_Environment($loader);
        // create array with URL parts in $url
        $this->splitUrl();
        // check for controller: no controller given ? then load start-page
        if (!$this->url_controller) {

            require APP . 'controller/Home.php';

            $page = new Home();
            $page->index($twig);
        }
        elseif (file_exists(APP . 'controller/' . $this->url_controller . '.php')) {
            // here we did check for controller: does such a controller exist ?

            // if so, then load this file and create this controller
            // example: if controller would be "car", then this line would translate into: $this->car = new car();
            require APP . 'controller/' . $this->url_controller . '.php';
            $this->url_controller = new $this->url_controller();
            // check for method: does such a method exist in the controller ?
            if (method_exists($this->url_controller, $this->url_action)) {
                if (!empty($this->url_params)) {
                    // Call the method and pass TWIG OBJECT 
                    if(get_class($this->url_controller) === "UserController"){
                        if($this->url_action === "registerNewUser"){
                            call_user_func_array(array($this->url_controller, $this->url_action), array($this->url_params));
                            exit;
                        }
                    }
                    call_user_func_array(array($this->url_controller, $this->url_params), $twig);

                } else {
                    // If no parameters are given, just call the method without parameters, like $this->home->method();
                    $this->url_controller->{$this->url_action}();
                }
            } else {
                if (strlen($this->url_action) == 0) {
                    // no action defined: call the default index() method of a selected controller
                    $this->url_controller->index();
                }
                else {
                   // header('location: ' . URL . 'error');
                    echo "404";
                }
            }
        } else {
           // header('location: ' . URL . 'error');
            echo "404";
        }
    }
    /**
     * Get and split the URL
     */
    private function splitUrl()
    {
       // $url = trim($_SERVER['REQUEST_URI'],"/");
        if (isset($_GET['url'])) {
            // split URL
            $url = trim($_GET['url'], '/');
            $url = filter_var($url, FILTER_SANITIZE_URL);
            $url = explode('/', $url);
            // Put URL parts into according properties
            // By the way, the syntax here is just a short form of if/else, called "Ternary Operators"
            // @see http://davidwalsh.name/php-shorthand-if-else-ternary-operators
            $this->url_controller = isset($url[0]) ? $url[0] : null;
            if(isset($url[0])){

                if($url[0] === "users"){
                    $this->url_controller = "UserController";
                }
            } else {
                 echo "waka";
                $this->url_controller = NULL;
            }
            $this->url_action = isset($url[1]) ? $url[1] : null;
            // Remove controller and action from the split URL
            unset($url[0], $url[1]);

            // Rebase array keys and store the URL params
            array_shift($_GET);
            $this->url_params = $_GET;

            #echo 'Controller: ' . $this->url_controller . '<br>';
           # echo 'Action: ' . $this->url_action . '<br>';
            #echo 'Parameters: ' . print_r($this->url_params, true) . '<br>';
        }
    }
}

Ther Daddyclass Controller

<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of Controller
 *
 * @author raviolican
 */
class Controller {
    //put your code here
    public $dbh = NULL;
    public $model = NULL;
    public $siteSettings = array();

    function __construct() { 
        $this->openDBConnection();
        $this->loadModel();
        $this->siteSettings = $this->model->getSiteConfiguration();

    }
    private function openDBConnection(){

         $this->dbh = new PDO('mysql:dbname=feedreader;host=localhost', "root", "");
         $this->dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

    }
    public function loadModel(){
        require 'models/Model.php';
        $this->model = new Model($this->dbh);
    }
}

Secondly the UserController.php This one is the extension of the Controller class, which actually creates the Model object.

<?php
/**
 * Description of userController
 *
 * @author raviolican
 */
class UserController extends Controller {
    //put your code here
    public function register(){
        require_once 'vendor/autoload.php';
        Twig_Autoloader::register();
        $loader = new Twig_Loader_Filesystem('views');
        $twig = new Twig_Environment($loader);
        echo $twig->render("user_register.twig", $this->siteSettings);
    }
    public function login(){
        require_once 'vendor/autoload.php';
        Twig_Autoloader::register();
        $loader = new Twig_Loader_Filesystem('views');
        $twig = new Twig_Environment($loader);
        echo $twig->render("user_login.twig", $this->siteSettings);
    }
    public function registerNewUser($userdata){
        // Match Password
        if(preg_match("/^(?=.*\d)(?=.*[a-zA-Z])\w{6,12}$/i", $userdata["regInputPWD"]))
        {
            // Check Password  match
            if ($userdata["regInputPWD"] === $userdata["regInputPWD_re"]) 
            {
                // Check  if eMail is valid
                if(filter_var($userdata["regInputEmail"], FILTER_VALIDATE_EMAIL))
                {
                    //Validate Catptcha
                    if($this->model->reCaptcha($userdata["g-recaptcha-response"]) === TRUE)
                    {
                   $this->model->registerNewUser($userdata); 
                }
                else {
                    echo "Captcha no valid";
                }

            } else {
                echo "E-Mail not valid";
            }
        } else {
            echo "Password don't match";
        }
    } else {
        echo "Password is not secure enought";
    }
}

}

Then the Model This is the Model which does the mysql stuff and API calls (ex. reCaptcha check)

<?php

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of db
 *
 * @author raviolican
 */
class Model {
    //put your code here
    private $database;
    function __construct($dbh) {
         $this->dbh = $dbh; 
    }
    private function __clone() {

    }
    /**
     * Querien the site's configurations from DB 
     * @return array Site Settings
     */
    public function getSiteConfiguration(){
        try {
            $sth = $this->dbh->prepare("SELECT * FROM site_settings");
            $sth->execute();
            $result = $sth->fetchAll()[0];

        } catch (PDOException  $e) { 
            echo "Database Error: Couldn't retrieve settings.<br>".$e->getMessage();
        } catch (Exception  $e) {
            echo "General Error: Couldn't retrieve settings.<br>".$e->getMessage();
        }
        return $result;
    }
    /**
     * Checks if user EXISTS in DB
     * @param type $email
     * @return boolean
     */
    private function checkUserMailExists($email){
        try {
            $sth = $this->dbh->prepare("SELECT * FROM `users` WHERE `email` = '$email'");
            $sth->execute();
            $result = $sth->rowCount();
            if ($result === 1) {
                return TRUE;
            }
            else {
                return FALSE;
            }
        } catch (PDOException $ex) {
            echo $ex->getMessage();
        }
    }
    /**
     * Registers new user when credentials match
     * @param array $userdata [regInputEmail], [regInputPWD] and [regInputPWD_re]
     * @throws Exception
     */
    public function registerNewUser($userdata) {
        if(!$this->checkUserMailExists($userdata["regInputEmail"])){
            try {
                $hashedPWD = password_hash($userdata["regInputPWD"], PASSWORD_BCRYPT, ['cost' => 11]);
                $sth = $this->dbh->prepare("INSERT INTO `users`"
                        . "(`id`, `categories`, `email`, `np_feeds`, `password`, `privatefeed`) "
                        . "VALUES('','hi','$userdata[regInputEmail]','NULL','$hashedPWD','NULL')");
                $sth->execute();
                echo "Registration done.";
            } catch (PDOException $ex) {
                echo "Database Error: Couldn't Insert User: " . $ex->getMessage();
            }
        }
    }
    /**
     * Does an API call to check captchas validity
     * @param string $response
     * @return boolean
     */
    public function reCaptcha($response){
        $secret = "6LcK5CQTAAAAAFSkYFGPsN4oCTKuRz4_LpjNQb-3";
        $result = json_decode(file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$secret.'&response='.$response),TRUE);
        if($result["success"] === TRUE){
            return TRUE;
        } else {
            return FALSE;
        }

    }
    public function sessionInit()

}

(I've created a GIT repository thats always latest code)https://github.com/raviolican/FeedReader)

My next step will be a secure login session handling. But where to place it? Where should I start the session? Should the session get started by the model constructor and also globals defined there?

\$\endgroup\$
  • \$\begingroup\$ Welcome to Code Review. I hope you get a lot of good answers. \$\endgroup\$ – pacmaninbw Jul 12 '16 at 17:02
  • \$\begingroup\$ You might get more views, votes and answers if you change the title and explain what your app is supposed to do. You might to look at the following help pages codereview.stackexchange.com/tour and codereview.stackexchange.com/help/how-to-ask \$\endgroup\$ – pacmaninbw Jul 12 '16 at 17:17
  • \$\begingroup\$ @pacmaninbw i changed very much now i hope its better :) thanks for your notifications \$\endgroup\$ – raviolican Jul 12 '16 at 17:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.