#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Location
    Ithaca
    Posts
    68
    Rep Power
    2

    A PHP GUI package in the making


    Well I have been designing a PHP GUI system to allow PHP to manipulate the creation of HTML elements. The design mostly uses Composite Design pattern, a GUI Component can be created and added to a GUI Container(a container is also technically, a component).

    Each component has a render method to execute the creation of HTML tags/attributes/styles, and by calling the top tier container's render method it is possible to render every component in one line of client code.

    Other than the components there are GUI Element Objects such as Align, Font and Color to take care of in-line css, while some GUI Helper Objects are also available to allow for easy creation of a system.

    Here is an example of a PHP form created using the GUI objects:
    PHP Code:
    <?php

    function __autoload($class) {
        
    // The autoload function, a bit messy if you ask me
        
    $class_path strtolower("../lib/class_{$class}"); 
        if(
    file_exists("{$class_path}.php")) include("{$class_path}.php");
        else{
              
    $abstract_path strtolower("../lib/abstract_{$class}");
            
    $interface_path strtolower("../lib/interface_{$class}");
            if(
    file_exists("{$abstract_path}.php")) include("{$abstract_path}.php");
            elseif(
    file_exists("{$interface_path}.php")) include("{$interface_path}.php");
            else throw new 
    Exception("Fatal Error: Class {$class} either does not exist!");
        } 
    }

    if(
    $_POST['submit']){
        echo 
    "Your Username is: {$_POST['username']}";
        echo 
    "<br>";
        echo 
    "Your Password is: {$_POST['password']}";
        echo 
    "<br>";
        echo 
    "Your Confirmed Password is: {$_POST['password2']}";
        echo 
    "<br>";
        echo 
    "Your Email is: {$_POST['email']}";
        echo 
    "<br>";
        echo 
    "Your Confirmed Email is: {$_POST['email2']}";
        echo 
    "<br>";
        echo 
    "Your Gender is: {$_POST['gender']}";
        echo 
    "<br>";
        echo 
    "Your Country is: {$_POST['country']}";
        echo 
    "<br>";
        if(empty(
    $_POST['username'])) echo "<b>Error: You have not entered a username, please go back and fill in the blank.</b>";
        elseif(empty(
    $_POST['password']) or $_POST['password'] != $_POST['password2']) echo "<b>Error: You have not entered a password, or you have not confirmed it successfully.</b>";
        elseif(empty(
    $_POST['email']) or $_POST['email'] != $_POST['email2']) echo "<b>Error: You have not entered an email, or you have not confirmed it successfully.</b>";
        else echo 
    "<b>You have registered successfully!</b>";
        return;
    }

    echo 
    "<center><b><u>Registration Form</u></b></center>";
    $form = new Form("myform");
    $form->setAction("test.php");
    $form->setMethod("post");
    $form->setAlign(new Align("center""middle"));

    $src = new URL("http://www.tivo.com/assets/images/abouttivo/resources/downloads/backgrounds/Green_bkgd_72rgb.jpg");
    $field = new FieldSet();
    $field->setLineBreak(FALSE);
    $field->setBackground(new Image($src"back"300));

    $field->add(new Legend("Required Field"));
    $field->add(new Division(new Comment("Please enter your username here, it must be alphanumeric."), "username"));
    $field->add(new TextField("username""admin"10));
    $field->add(new Paragraph(new Comment("Please fill in your password confirmed password here.")));
    $field->add(new PasswordField("password""password""123456"));
    $field->add(new PasswordField("password""password2"));

    $email = new Paragraph();
    $email->setID("email");
    $email->setFont(new Font(14"Times New Roman"));
    $email->getFont()->setWeight("bolder");
    $email->setForeground(new Color("#000080"));

    $email->add(new Comment("Please type your email and confirmed email here."TRUE));
    $email->add(new PasswordField("email""email"));
    $email->add(new PasswordField("email""email2"));
    $field->add($email);

    $field2 = new FieldSet(new Legend("Additional Fields"));
    $field2->setBackground(new Color("red"));

    $radiolist = new RadioList("gender");
    $radiolist->add(new RadioButton("Male""gender""male"));
    $radiolist->add(new RadioButton("Female""gender""female"));
    $radiolist->add(new RadioButton("Unknown""gender""unknown"));
    $radiolist->check("unknown");

    $countries = array("Britain""France""Germany""Italy""Spain""America""Canada""Russia""Australia");
    $alias = array("gbr""fra""ger""ita""esp""usa""can""rus""aus");
    $default "usa";
    $dropdown = new DropdownList("country");
    $dropdown->fill($countries$alias$default);

    $comment2 = new Comment("Your Citizenship: "FALSE);
    $comment2->setBold(TRUE);
    $comment2->setUnderlined(TRUE);
    $comment2->setForeground(new Color("yellow"));

    $field2->add(new Comment("Your Gender: "FALSE));
    $field2->add($radiolist);
    $field2->add($comment2);
    $field2->add($dropdown);

    $submit = new Button("Register""submit""submit");
    $submit->setLineBreak(FALSE);

    $form->add($field);
    $form->add($field2);
    $form->add(new Image(new URL("../templates/icons/facebook.gif"), "facebook"20));
    $form->add($submit);
    $form->add(new Image(new URL("../templates/icons/twitter.gif"), "twitter"20));
    echo 
    $form->render();
    ?>
    The screenshots for the form is shown below:


    As you can see from above, calling the render method on the form object results in all of its components/sub-containers to be rendered, finally displaying a neatly looking form on the screen. Tbh I aint really quite good at designing the render system, the code for render method is somewhat messy and has lots of repetition. I was wondering if anyone of you could give me some advices on how to design a better render method for each object, Id appreciate this.


    The demo for GUI Package v0.8 can be downloaded below. It pretty much has all functionality now, still need to add a few more stuff and wraps up the package in the end:
    http://www.mediafire.com/?9spu6adizc5iq1i
  2. #2
  3. --
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Jul 2012
    Posts
    3,959
    Rep Power
    1014
    Hi,

    interesting approach. This reminds me of GTK and Qt.

    I cannot really comment on the code, because I haven't looked at it in detail, but I do have some general criticism:

    When you generate the HTML elements and set their style at the same time, you break the separation of content and design that people are fighting so hard for. You basically go back to the "old HTML" with all the <blink> and <font> and whatnot. And this isn't just some academic theory. Imagine a web designer who wants to redesign parts of a website. Even though the actual content of the page doesn't change at all, he would have to go through all of your PHP code just to change the design of some elements. It's also gigantic effort to set the style for each element individually as opposed to using CSS. There's a reason why it's "cascading style sheets".

    Another problem is that object-oriented code is by far the most cumbersome, most unreadable and most inefficient way to make designs. In HTML, you just write down nested tag pairs and attributes. In PHP, you have to explicitly create each element (in your case even the attributes), then set its properties, then add it to its parent element. Just compare your table code (~75 lines, ~2400 characters) with the same table made with plain HTML and CSS.

    So this is certainly an interesting project for learning OOP. But I doubt it has a practical use.

    I think "the future" (what a big word) lies in specialized template languages. If you look at, for example, Haml for Ruby, that's pretty much what I would consider as ideal.
  4. #3
  5. Mad Scientist
    Devshed Expert (3500 - 3999 posts)

    Join Date
    Oct 2007
    Location
    North Yorkshire, UK
    Posts
    3,661
    Rep Power
    4123
    I agree with Jacques1's comments

    Following on from Jacques1's comments, an intermediary step would be to utilise the element's constructor and pass in the values tat way and drop old style fonts for in-line styles at the very least

    for example: your example

    $email = new Paragraph();
    $email->setID("email");
    $email->setFont(new Font(14, "Times New Roman"));
    $email->getFont()->setWeight("bolder");
    $email->setForeground(new Color("#000080"));

    would become

    PHP Code:
    $email = new Paragraph(array(
        
    "id"=>"email",
        
    "style"=>new Style(array(
            
    "font-family":"Times New Roman",
            
    "font-size":"14px",
            
    "font-weight":"bolder",
            
    "color":"#000080"
        
    ))
    )); 
    [this comes from my love of javascript and the use of configuration objects]

    going forwards, the separation of data and style could be further achieved by the use of attributes only; then an empty CSS file could be produced detailing all classes / selectors used. The designer can then use this to style the html
    I said I didn't like ORM!!! <?php $this->model->update($this->request->resources[0])->set($this->request->getData())->getData('count'); ?>

    PDO vs mysql_* functions: Find a Migration Guide Here

    [ Xeneco - T'interweb Development ] - [ Are you a Help Vampire? ] - [ Read The manual! ] - [ W3 methods - GET, POST, etc ] - [ Web Design Hell ]
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Dec 2012
    Location
    Ithaca
    Posts
    68
    Rep Power
    2
    @ Jacques1:

    Thanks for your comment. I understand what you are saying, this is not gonna really be useful for large enterprise applications in which you have highly specialized coders and designers working on completely separate aspect. For this reason, its usefulness is hindered.

    It does work for certain situations. Take myself as an example, in my application the designer is pretty much an artist or a styler, she works on the images, the css and the main layout. The layout looks like this:


    As you see, the layout has a few major blocks. The designers work on the background/banner image, the core layout and the construction of menu, sidebar and footer. These widgets stay the same all the time(though the sidebar may differ from admin to user and guest), so the designer pretty much only works on one template file per theme. My designers do work on multiple themes, since we have a 'style switcher'.

    What really is changing from page to page is the document title and the document content. The fact is that, well, I as the coder is the one who builds these two widgets. Their contents are being controlled by AppControllers, which calls their corresponding Views. In my case the Views are actually classes instead of html/tpl templates, these classes are constructed using GUI components. At the very end, the document content is rendered and sent to the template file, whose position can be manipulated by the designer. The actual materials of the document title and content however, are never touched directly by a designer.

    You may see this is weird, I agree. The issue is that if I want my designer to actually work on construction of HTML tables and forms for every page, shes gone or just not able to do it quickly. Think about the amount of time dedicated to create a complicated html table whose data is pulled from database and formatted before outputting to the page. There sure is even quite a bit of business logic involved.

    Regarding the table construction being cumbersome... Well yeah, to create a standard table it is annoying to have to write this many lines, thats what I cannot deny. In most cases however, the table data comes from database fields or formatted fields. This is why I implement a TableBuilder class, it can generate a table from a database table with supplied data fields easily. Moreover, each field can be formatted with a table helper method. For instance, you can use the TableHelper::getImage($field) method to convert an image src to a well-rendered HTML image.

    So to summarize, I completely realize what you are saying and for most commercial softwares with highly specialized dev team, it wont help at all. I do believe it will work well in certain cases, anyway every application is different. Dont you think so?



    @Northie:
    I appreciate your input too. Its actually an interesting idea to consider adding css configuration data to each GUIComponent constructor. I did not implement it before 'cause I dont feel that inline css will be used frequently, after all a main css will do the trick most of the time. Still, if it gives people an extra degree of flexibility I will seriously consider. After all, this system is built to be flexible, I even include TableBuilder and FormBuilder classes to simplify the construction of HTML tables and forms in certain applications. If you have more recommendations or criticism to make, please feel free doing so. I'd love to hear.


    Update:
    I have completed the GUI package version 0.9. I added new features such as the ability to create an IFrame. More importantly, I fixed up those messy render methods. The new design makes good use of inheritance, I give them a much cleaner and organized look. Many classes simply do not even need a render method, others call parent render method and add their own implementation. Moreover, I am using lazy load in the rendering process, the object stores a list of attributes and css elements, and renders only those that have been set. This way it does not go through all render methods and checks if a property is even set or not. It may increase memory usage, but sure improves the speed to a great deal.

    There are exceptions though, one of them is Table Cell since it can serve as both a non-container(holds text), or a container type object. Rendering such objects can be a pain, I am considering subclassing the original Table Cell class to separate the table cell container from table cell noncontainer.

    Here is the sample code for table builder btw, I feel it is easier for programmers to use than to implement a while/for loop to pull data from database. Dont mind that database object though, its basically a modified version of PDO(it extends PDO though):

    PHP Code:
    function __autoload($class) {
        
    // The autoload function, a bit messy if you ask me
        
    $class_path strtolower("../lib/class_{$class}"); 
        if(
    file_exists("{$class_path}.php")) include("{$class_path}.php");
        else{
              
    $abstract_path strtolower("../lib/abstract_{$class}");
            
    $interface_path strtolower("../lib/interface_{$class}");
            if(
    file_exists("{$abstract_path}.php")) include("{$abstract_path}.php");
            elseif(
    file_exists("{$interface_path}.php")) include("{$interface_path}.php");
            else throw new 
    Exception("Fatal Error: Class {$class} either does not exist!");
        } 
    }

    include(
    "../inc/config.php");
    $db = new Database(DBNAMEDBHOSTDBUSERDBPASSPREFIX);
    $fields = array("id""category""itemname""description""imageurl""price");
    $stmt $db->select("items"$fields"price != 0");

    $table = new TableBuilder;
    $table->setAlign(new Align("center""middle"));
    $table->setWidth(800);
    $table->buildHeaders("ID""Category""Itemname""Description""Image""Price""Edit""Delete");
    $table->setHelper(new TableHelper($table));
    $fields = array("id""category""itemname""description""imageurl""price""itemname::edit""itemname::delete");
    $table->setMethod($fields[4], "getImage");
    $table->setMethod($fields[6], "getEditLink");
    $table->setMethod($fields[7], "getDeleteLink");
    $table->buildTable($stmt$fields);
    echo 
    $table->render(); 
    The new demo can be downloaded as below, please lemme know what you think I should fix before the version 1.0 release. Thx.
    http://www.mediafire.com/?c6r9iy9n6mq7anl

IMN logo majestic logo threadwatch logo seochat tools logo