Framework Design Help

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Post Reply
User avatar
shiznatix
DevNet Master
Posts: 2745
Joined: Tue Dec 28, 2004 5:57 pm
Location: Tallinn, Estonia
Contact:

Framework Design Help

Post by shiznatix »

This is kinda complicated so if you need anything clarified please let me know

I am (trying) to make my own framework for my future projects and for a bit of a thing to put on a resume maybe. mostly for future projects. what my main idea is, is to have modules or pages. each page can have the 3 levels of classes or just 1 level, whatever you want. then when you go to a page like mysite.org/SomeThing.php it will load the view class of the SomeThing module and whatnot. This works great. But that only works if every page is different.

What I am trying to do:

I want to be able to specify that I am going to be using 1 main template. This means I want to have 1 main module load all the other modules that will go into the main template. this works right now but with this problem:

i go to the page for the 1st time in that session. the default views for each loaded module are loaded and shown. Each module can have different 'views' like the login module would have the html forum at first then it would show the 'welcome ******' after you login which is a seperate 'view' for that module.

what i need is a way to make sure that the login module will now always show the 'welcome ******' until the user logs out. i can do this using only the main template module and doing a billion if else things but that seams to be too much and i want the framework to do that for me. what i originally thought to do (and is still implimented) is to save the previous view for each module in a session then when a module is loaded check what the last view was. this would work (maybe) but i don't think is quite flexable enough and could make the sessions too big (maybe). Is there a better way?

Here is the main classes that do the bulk of the work and an example module:

Code: Select all

<?php

class Content
{
    private $View;
    private $Page;

    private $UI;
    private $Controller;
    public $SubClass;

    public function __construct($Page)
    {
        $this->Page = $Page;

        ToDo('this require of the view every time might be stupid');

        require_once PAGES_PATH.$Page.'/'.$Page.'.View.class.php';

        if (false !== IS_SINGLE_TEMPLATE)
        {
            require_once PAGES_PATH.SINGLE_TEMPLATE.'/'.SINGLE_TEMPLATE.'.View.class.php';

            $UIClass = SINGLE_TEMPLATE.'View';
            $SubClass = $this->Page.'View';
            $this->SubClass = new $SubClass;
        }
        else
        {
            $UIClass = $this->Page.'View';
        }

        $this->UI = new $UIClass;

        $this->View = $this->GetView();
    }

    public function GetContent()
    {
        if (false !== IS_SINGLE_TEMPLATE)
        {
            $this->SubClass->View = $this->View;

            if (method_exists('View'.$this->View, get_class($this->UI)))
            {
                $function = 'View'.$this->View;
            }
            else
            {
                $function = 'ViewMain';
            }

            return $this->UI->$function();
        }
        else
        {
            $function = 'View'.$this->View;
            return $this->UI->$function();
        }
    }

    public function GetView()
    {
        if (0 !== count($_POST))
        {
            if (!empty($_POST['View']))
            {
                foreach ($_POST['View'] as $key => $val)
                {
                    return $key;
                }
            }
            else if (!empty($_POST['Action']))
            {
                foreach ($_POST['Action'] as $key => $val)
                {
                    return $this->DoAction($key);
                }
            }
        }

        if (0 !== count($_GET))
        {
            if (!empty($_GET['View']))
            {
                return $_GET['View'];
            }
            else if (!empty($_GET['Action']))
            {
                return $this->DoAction($_GET['Action']);
            }
        }
        
        return 'Main';
    }

    function DoAction($function)
    {
        require_once PAGES_PATH.$this->Page.'/'.$this->Page.'.Controller.class.php';

        $ControllerClass = $this->Page.'Controller';

        $this->Controller = new $ControllerClass;

        $this->Controller->$function();

        if (empty($this->Controller->View))
        {
            return 'Main';
        }
        else
        {
            return $this->Controller->View;
        }
    }

    function MakeHeader()
    {
        $c = '';
        $c .= '<html>';
        $c .= '  <head>';
        $c .= '    <title>'.$this->Page.' - natixFrameWork </title>';
        $c .= '  </head>';
        $c .= '  <body>';

        return $c;
    }

    function MakeFooter()
    {
        $c = '';
        $c .= '  </body>';
        $c .= '</html>';

        return $c;
    }
}

?>

Code: Select all

<?php

class Base
{
    public $db;
    public $Data;
    public $Extenions;
    public $Errors;
    public $View = '';
    public $PageView = false;

    public function __construct()
    {
        global $db;
        $this->db =& $db;
        global $Extensions;
        $this->Extensions =& $Extensions;
    }

    public function GetList($fields = null, $conditions = null, $mode = 'AND', $tail = null)
    {
        $this->db->Select($this->Table, $fields, $conditions, $mode, $tail);
        return $this->db->GetDBVarsList(get_class($this));
    }

    public function Load($conditions = null, $mode = 'AND', $tail = null)
    {
        $this->db->Select($this->Table, false, $conditions, $mode, $tail);
        $DBVars = $this->db->GetDBVars();

        if (empty($DBVars))
        {
            return false;
        }

        $ClassVars = get_class_vars(get_class($this));

        foreach ($ClassVars as $key => $val)
        {
            if (array_key_exists($key, $DBVars))
            {
                $this->$key = $DBVars[$key];
            }
        }
    }

    public function SetVars($vars)
    {
        foreach ($vars as $key => $val)
        {
            $this->$key = $val;
        }
    }

    public function LoadClass($class, $level)
    {
        require_once PAGES_PATH.$class.'/'.$class.'.'.$level.'.class.php';

        $ClassName = $class.$level;

        $tmp = new $ClassName;

        return $tmp;
    }

    public function AutoSet($vars)
    {
        if (is_array($vars))
        {
            $ClassVars = get_class_vars(get_class($this));

            foreach ($vars as $key => $val)
            {
                if (array_key_exists($key, $ClassVars))
                {
                    $this->Set($key, $val);
                }
            }

            return true;
        }
        else
        {
            return false;
        }
    }

    public function Set($var, $val)
    {
        $ClassVars = get_class_vars(get_class($this));

        if (array_key_exists($var, $ClassVars))
        {
            $this->$var = $val;
            return true;
        }
        else
        {
            return false;
        }
    }

    public function SetView($view)
    {
        $this->View = $view;
        $this->SetPreviousView();
    }

    public function ShowView()
    {
        if ('' === $this->View)
        {
            $this->View = 'Main';
        }

        $function = 'View'.$this->View;

        return $this->$function();
    }

    public function Save()
    {
        $skip = array('Table', 'Data', 'Id', 'db', 'Extensions');

        if (empty($this->Id))
        {
            foreach ($this as $key => $val)
            {
                if (!in_array($key, $skip) && '' != $val)
                {
                    $fields[] = $key;
                    $values[] = $val;
                }
            }

            $this->db->Insert($this->Table, $fields, $values);
        }
        else
        {
            foreach ($this as $key => $val)
            {
                if (!in_array($key, $skip) && '' != $val)
                {
                    $set[$key] = $val;
                }
            }

            $this->db->Update($this->Table, $set, array('Id' => $this->Id));
        }
    }

    public function Remove($conditions, $mode = 'AND')
    {
        $this->db->Remove($this->Table, $conditions, $mode);
    }

    public function Get($var)
    {
        $ClassVars = get_class_vars(get_class($this));

        if (array_key_exists($var, $ClassVars))
        {
            return $this->$var;
        }
        else
        {
            ToDo('trigger an error here');
            return false;
        }
    }

    public function LoadExtension($extension, $params = false)
    {
        return $this->Extensions->$extension($params);
    }

    public function SetError($message)
    {
        $this->Errors[] = $message;
    }

    public function GetErrors()
    {
        return $this->Errors;
    }

    public function isErrors()
    {
        if (is_array($this->Errors))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public function SetPreviousView()
    {
        $class = str_replace('Controller', 'View', get_class($this));
        $_SESSION['PreviousViews'][$class] = ('' !== $this->View ? $this->View : 'Main');
        return true;
    }

    public function LoadViews()
    {
        global $Content;

        foreach ($this->Data as $key => $val)
        {
            if (get_class($val) == get_class($Content->SubClass))
            {
                $this->Data[$key]->View = $Content->SubClass->View;
            }
            else if (isset($_SESSION['PreviousViews']) && array_key_exists(get_class($val), $_SESSION['PreviousViews']))
            {
                $this->Data[$key]->View = $_SESSION['PreviousViews'][get_class($val)];
            }
        }
    }
}

?>

Code: Select all

<?php

class LoginController extends Base
{
    public function __construct()
    {
        parent::__construct();

        $this->Data['Login'] = $this->LoadClass('Login', 'Model');
    }

    public function Login()
    {
        $LI =& $this->Data['Login'];

        $this->LoadExtension('SHA256');

        if (false !== $LI->AutoSet($_POST))
        {
            if ('' == $LI->Get('Username'))
            {
                $this->SetError('You must enter a username');
            }
            if ('' == $LI->Get('Password'))
            {
                $this->SetError('You must enter a password');
            }

            if (false === $this->isErrors())
            {
                $LI->Set('Password', SHA256::hash($LI->Get('Password')));

                $UsersList = $LI->GetList('*', array('Username' => $LI->Get('Username'), 'Password' => $LI->Get('Password')), 'AND', 'LIMIT 1');
    
                if (1 === $LI->db->GetCount())
                {
                    $LI->Set('Id', $UsersList[0]->Get('Id'));
                }
                else
                {
                    $this->SetError('Invalid username or password');
                }
            }

            if (false !== $this->isErrors())
            {
                dump($this->GetErrors());
            }
            else
            {
                $LI->Set('LastLogin', time());
                $LI->Save();

                $_SESSION['User'] = array(
                  'Id' => $LI->Get('Id'),
                  'Username' => $LI->Get('Username'),
                  'Password' => $LI->Get('Password'),
                );

                $this->SetView('Welcome');
            }
        }
    }
}

?>
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

It is difficult to understand what you are trying to do. And the names Content and Base don't mean much to me in the sense that you are using them. They look like View and Model classes. And your question seemed to be about showing information about the user on the main template -- so probably a User object would be the Model for that outer View.
(#10850)
User avatar
shiznatix
DevNet Master
Posts: 2745
Joined: Tue Dec 28, 2004 5:57 pm
Location: Tallinn, Estonia
Contact:

Post by shiznatix »

ok sorry for the lack of explanation of the classes:

the content class is loaded and will first see if there was an 'Action' in the get or post and if so will preform that action on the page (the page being the module) then it will get the view that was set (defaults to Main if none was specified) and returns that View method.

the base class is like all the functions that might be needed in a module, every module layer extends the base class.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I am having a hard time grasping the whole thing. The View is also called Content and UI. I'm not sure what is what. And the Base class has View stuff but also has database Gateway methods. I am confused.
(#10850)
User avatar
shiznatix
DevNet Master
Posts: 2745
Joined: Tue Dec 28, 2004 5:57 pm
Location: Tallinn, Estonia
Contact:

Post by shiznatix »

hurmmmm i thought this would happen. ill just post a small thing here...

if anyone who knows some OOP wants to help me make a framework im glad for the help as long as we can make it open source and credit all parties who contributed. i have a good start but need some help with some things.

if anyone else thinks that if they saw more code they could understand i can send you a zip file with all the source in it. posting more code here would just confuse people more.

if anyone wants to give me some one on one advise that would also be great.

maybe this should kinda be in the volunteer section?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Post a link to download runable code and I would be glad to take a look at it.
(#10850)
User avatar
Luke
The Ninja Space Mod
Posts: 6424
Joined: Fri Aug 05, 2005 1:53 pm
Location: Paradise, CA

Post by Luke »

Shizzy... I think I am working on building the same thing as you. I am looking for a way to have a client log in, and depending on what privileges that user has, there will be a number of modules available for him/her to use such as a file manager, mass mail, basic content management, etc. I am looking for a standard set of classes that would allow for low-level tasks such as session handling and database connection, but I do not want to be tied to model-view-controller. I would like that to be optional. Is this anywhere near what you are looking to do or am I way off?
User avatar
shiznatix
DevNet Master
Posts: 2745
Joined: Tue Dec 28, 2004 5:57 pm
Location: Tallinn, Estonia
Contact:

Post by shiznatix »

http://shiznatix.imaginationdesigns.org/15.07.06.zip -- to download what i have right now.

http://shiznatix.imaginationdesigns.org/14.07.06.zip -- to download what i had before i tried to solve the problems that i have now (the one that works with just 1 page loaded at a time)

the newest version might be a little bit of a mess because i was trying a bunch of things to get the idea down.

The Ninja Space Goat: the idea is simmilar and the framework i want to design should be able to do what you described. the optional 3 levels of classes is maybe but i want to make it manditory for now then try to make it optional later. i am not looking to build what you described but i want to make the framework that would make it easy and organized to make such a thing. if you are interested in helping look over the files i linked to and let me know what you think.

if anyone that does look at my stuff thinks im going in the wrong direction or that what i have is crap let me know so i don't keep going on what i have and so i can try a new idea.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I downloaded your latest and will look through it when I get a little time today. Thanks.
(#10850)
User avatar
shiznatix
DevNet Master
Posts: 2745
Joined: Tue Dec 28, 2004 5:57 pm
Location: Tallinn, Estonia
Contact:

Post by shiznatix »

arborint wrote:I downloaded your latest and will look through it when I get a little time today. Thanks.
no, thank you.
Post Reply