Showing posts with label design pattern. Show all posts
Showing posts with label design pattern. Show all posts

Thursday, July 2, 2015

myFrontController v0.3

Note: The blog posts are written based on the notes I make on the readMe.txt file. Some the actions where "to do" items which were implemented later, for this reason you may see text like "I should do that"

Major improvements in v0.3
- autoloading function
- routing
- give up admin/index  (unique point of entry in the application)
- improvements to the login flow

1. Autoloading
 As you could see in the post about version 0.2 there are some issues with the autoloading function. I decided to improve this and even more use a popular standard PSR-4. My autoload function is inspired from this one:  http://www.php-fig.org/psr/psr-4/examples/  - just that I do not have the path  /src/ directory. I  started using also  namespaces in order to  to respects the PSR-4 standard and maybe later I will be able to use packages built by other people together with myFrontController CMS.

My vendor\package combination of namespaces is :  CPANA\myFrontController ,under this I have added :

CPANA\myFrontController\controller
CPANA\myFrontController\model
......

I had to change some code in my FrontController class as it seems there is a known bug (weird behaviour ) :      when I try to dynamically create the name of the class  "new $_GET['controller']()" I get message that the class cannot be found
 Here are some links about this subject:
http://stackoverflow.com/questions/6150703/php-dynamic-instance-with-not-fully-qualified-namespaces
    https://bugs.php.net/bug.php?id=51126
       
This is the code to  solve the problem:
  
                $class_name=__NAMESPACE__ . '\\'. $_GET['controller'];
                $obj= new $class_name();
                $obj->$_GET['action']();

2. Routing

I started reading the Symfony Book and I  implemented a routing system inspired from the one used in Symfony.
The logic to call the correct function will be :
    1. read the requested URL ($_SERVER['REQUEST_URI']), and exclude the /myFrontController
    2. verify in the \config\route.xml if there is any route matching -> if yes than read from \config\route.xml the function and call it.
            -> if no redirect to 404 page - created new controller class called "PageNotFound.class.php"

So I did the following:

1. created \config\route.xml file to store routes and matching class and method to be called
2. modified FrontControll class
3. added .htaccess from Symfony and replaced to redirect to "index"    instead of "app"                                                               

3. Give up admin/index

-in order to use just one front controller (not one for normal user and one for admin user) some changes should be made (also taking in account the new routing system)
-this will involve changing the way the pages are rendered (templating?) maybe request and response objects
---->>>
-new class \view\Render.class.php
    -it contains a static property $content  which is echoed in content.php  and also $menu which depends on being an admin or normal user
    -and a method which renders the main_template.php  (which imports content.php and menu.php or menu_admin.php)
    -each time we want to change the output, I change the value of the $content and call the Render::renderPage()
   
4. Login

I modified the LoginUser.class.php and also the Admin.class.php

-in Admin.class.php the function "renderLogin" it is called both when clicking "Admin" button and also when clicking on the Submit button
-in Login.class.php I added the static function validateLoginAdmin() which is used to check which menu (admin or normal user one) should be displayed. at the moment I call it on each specific class (Home, Blog) but it should be moved in to Render




5. Overview
At this point if you want to see the Home page the flow of the application is the following:
-you are redirected to index.php
-the front controller searches the path in router.xml and calls the controller (the needed method for the job)
-the method getHome() from StaticPages class is called from controllers __contruct(), which furher calles fetchStaticInfo($pagetype) from DBCon class. The information is fetched from database
- the render() function from controller class is called




The files can be downloaded at this link.

Wednesday, July 1, 2015

myFrontController v0.2

Usually the continuation of a good movie is bad, hopefully my version 0.2 of myFrontController is a real progress.


I moved the files inside specific folders like: controllers, model, login, admin etc. Doing this means I need to implement a more complex autoloading function.

$folders=array('\\controller\\','\\model\\','\\login\\','\\view\\');
   
    foreach($folders as $folder){
       
       if(file_exists($dir . $folder . $class . '.class.php')){
            require_once $dir . $folder . $class . '.class.php';
        }


It is not covering some situations for this reason you may see some "include" in some classes, but I promise to solve the issue in v0.3

I am trying to start using comments in the style used by PHP Documentor. Step by step I hope to get used to write them. An  IDE would probably automatically generate the comments skeleton but at the moment I am using Notepad++

In the image below it is more or less described how my website works and a little on how I implemented the separation of concerns following the MVC design pattern ideas.



Changes from version 0.1 of myFrontController:

added DBCon.class.php - handles connection to database and fetching data

added StaticPages.classes.php -
added BlogModel.classes.php

- replace & with & in the links

----------- database --------------------------------
shift from SQLite to MySQL
create database "myblog"
create table  static_pages
alter table blogposts add column title varchar(255)


----------------------------------------------------------------------------------------------------------------------------------------
added basic login module (based on cookies) to the have an Admin view from where you can add new posts
added:
index_admin.php
/controller/Admin.class.php
/login/LoginUser.class.php

--------------------------------------------------
login module explained:
    first I hardcoded the username and passord inside the static function validateUserPass of the class LoginUser
    ---
    static public function validateUserPass($user,$pass){
            if(($user=='admin')&&($pass=='1234')){
                return true;

    ---

    From a form, username and password are sent via POST method using hidden fields (login.php):

            <form action="index.php" method="POST" >
                Username <br>
                <input type="text" name="username">
                <br>Password <br>
                <input type="text" name="password">
                <input type="submit" value="Login">
                <input type="hidden" name="controller" value="Admin">
                <input type="hidden" name="action" value="validateLogin">
            </form>

    ---
    the hidden values indicate controller name "Admin" and action "validateLogin"

    if the user and password match the ones hardcoded than we set a cookie containing an md5 hash of the user name + a secret word.

     setcookie('PageLogin', md5($user.self::$secret_word));
     setcookie('PageLoginUser', $user);


The files can be downloaded from this link:  https://drive.google.com/file/d/0B4lszAGYHn-dTXNOX2psd2QweGc/view?usp=sharing

myFrontController v0.1

NOTE: I am telling here how I got from point A to point B, not that it is the recommended path.

I started thinking on my Front controller based website from the point of view of a link containing a query string, like this one:

 "https://en.wikipedia.org/w/index.php?title=Main_Page&oldid=664887982"



So the query says that the request will be processed by the file index.php and the $_GET['title'] will be set with the value "Main_Page" and the $_GET['oldid'] will be set with value 664887982.

my links will look  like this (under ..\EasyPHP-DevServer-14.1VC9\data\localweb  I created the folder "myFrontController"):

'http://127.0.0.1/myFrontController/index.php?controller=Home&action=render'

You can read this link like this: index.php should process this request and call the method "render()" of the class "Home"

I will create an index file, a FrontController class, and other controller classes for each functionality I want to implement: Home page, Blog listing page. I will add also a folder called "templates" to store... well the templates.
I created a header and a footer and included them in the index.php

include("templates/header.php");

FrontController::set_controller();
 

include("templates/footer.php");


 OK, so let's move on to the actual FrontController class: it contains a static class called  setController() which reads the values for 'controller' and 'action' from $_GET[] and dynamically create an instance of the specified class and calls the method


            if((!isset($_GET['controller']))||(!isset($_GET['action']))){
       
                echo "do nothing GET";
            }else{
       
                //call controller class for GET method
                $obj= new $_GET['controller']();
                $obj->$_GET['action']();

                   


The second functionality that I want to implement is to list the blog post. I am using SQLite to store the information. You should execute the file "initializeSQLite.php" (you can just navigate to it on your browser) to create an SQLite database, create the tables BlogPosts and store information.

In the Blog.class.php is found the code for reading the database and generate the output.

The third functionality is adding a new post, the link is this one:   '?controller=Blog&action=new_post_entry'

The functionality is done it two steps:
- first step include "templates/new_post_entry.php" which contains a form where you can fill the title of the post, author, post content and a Submit button.
-second step when clicking the Submit button the request goes to index.php (again). together with the data the form contains 2 hidden fields :

     <input type="hidden" name="controller" value="Blog">
    <input type="hidden" name="action" value="postOnBlog">


These two values indicate to FrontController which method/class will handle the request.

Below is the list of files at the end.
You can download the code from here:  https://drive.google.com/file/d/0B4lszAGYHn-dVFh0X0E2NV9BLW8/view?usp=sharing