5
\$\begingroup\$

Pvik is a lighweight PHP framework that uses the model, view, controller principle.

-- EXAMPLE --

Here is a very simple example how you build a website with the framework. I'm asking you if this is easy to understand or just for me because I know the framework and of course if there are things that I can build better. Our sample database looks like this:

Authors
- AuthorID (int, primarykey, auto increment)
- Firstname (text)
- Lastname (text)

Books
- BookID (int, primarykey, auto increment)
- Title (text)
- AuthorID (int)

At first we have to tell Pvik how our database looks like. So we're creating a ModelTable that has field definitions and also Model which will be used as object for a single line (in folder /model/):

<?php
class AuthorsModelTable extends ModelTable {
    public function __construct(){
        // define the table name
        $this->TableName = 'Authors';
        // define the class name for the model
        // 'Model' is the standard suffix: 'AuthorModel'
        $this->ModelName = 'Author';
        // define the primarykey
        $this->PrimaryKeyName = 'AuthorID';
        // define a new attribute from type primary key
        $this->FieldDefinition['AuthorID'] = array ('Type' => 'PrimaryKey');
        // define a new attribute from type normal (text, number, anything)
        $this->FieldDefinition['Firstname'] =  array ('Type' => 'Normal');
        // define a new attribute from type normal (text, number, anything)
        $this->FieldDefinition['Lastname'] =  array ('Type' => 'Normal');
        // define a new attribute from type many foreign object
        // this field contains an ModelArray from 'BookModel's that are associated with a author
        $this->FieldDefinition['Books'] = array ('Type' => 'ManyForeignObjects', 'ModelTable' => 'Books','ForeignKey' => 'AuthorID');
    }
}
// this phpdoc is usefull for code completion
/**
 * @property int $AuthorID
 * @property string $Firstname
 * @property string $Lastname
 * @porperty ModelArray $Books
 */
class AuthorModel extends Model {
    public function __construct(){
        // define the class name for the model table
        // 'ModelTable' is the standard suffix: 'AuthorsModelTable'
        $this->ModelTableName = 'Authors';
    }
}
?>

and now for books:

<?php

class BooksModelTable extends ModelTable {

    public function __construct() {
        // define the table name
        $this->TableName = 'Books';
        // define the class name for the model
        // 'Model' is the standard suffix: 'BookModel'
        $this->ModelName = 'Book';
        // define the primarykey
        $this->PrimaryKeyName = 'BookID';
        // define a new attribute from type primary key
        $this->FieldDefinition['BookID'] = array('Type' => 'PrimaryKey');
        // define a new attribute from type normal (text, number, anything)
        $this->FieldDefinition['Title'] = array('Type' => 'Normal');
        // define a new attribute from type foreign key
        // this field contains the real id
        $this->FieldDefinition['AuthorID'] = array('Type' => 'ForeignKey', 'ModelTable' => 'Authors');
        // define a new attribute from type foreign object
        // this field contains a object from type 'AuthorModel'
        $this->FieldDefinition['Author'] = array('Type' => 'ForeignObject', 'ForeignKey' => 'AuthorID');
    }

}

// this phpdoc is usefull for code completion
/**
 * @property int $BookID
 * @property string $Title
 * @property int $AuthorID
 * @property AuthorModel $Author
 */
class BookModel extends Model {

    public function __construct() {
        // define the class name for the model table
        // 'ModelTable' is the standard suffix: 'BooksModelTable'
        $this->ModelTableName = 'Books';
    }

}

?>

Now Pvik knows everthing about our database (I skip the part where in the config we fill in the login data). The next step is creating a controller (in folder /controllers/), I don't want to overfill this post, so the controller just loads the data and refers to the view.

<?php
class BooksController extends Controller {
    // action                  
    public function Overview(){
       // load all books
       $Books = ModelTable::Get('Books')->LoadAll();
       // passing the data to the view
       $this->ViewData->Set('Books', $Books);
       $this->ExecuteView();
    }              
}
?>

and of course the view (in /views/books/overview.php #/views/controller name/action name.php ):

<!DOCTYPE html>
<html>
   <head>
       <title>All books</title>
   </head>
   <body>
       <?php
           // getting the data from the controller
           $Books = $this->ViewData->Get('Books');
           /* @var $Books ModelArray */
        ?>
       <table>
            <tr><th>Title</th><th>Author</th><th>How many books did the author write?</th></tr>
            <?php 
            foreach($Books as $Book){
                /* @var $Book BookModel */
                ?>
                <tr>
                    <td><?php echo $Book->Title;?></td>
                    <!-- Uses lazy loading to get the author -->
                    <td><?php echo $Book->Author->Firstname . ' ' . $Book->Author->Lastname ?></td>
                    <td><?php echo count($Book->Author->Books);?></td>
                </tr>
                <?php
            }
            ?>
        </table>
    </body>
</html>

The last step is that we have to tell pvik which controller should be called when. Therefor we add a route in the config.php:

self::$Config['Routes'] = array (
    array ('Url' => '/books/', 'Controller' => 'Books', 'Action' => 'Overview')
);

If we would access our side now under the URL example.org/books/ Pvik automatically calls the controller, which loads a list of books. Than the view get called which does create the HTML.

Pvik also provides methods to insert/update Models. You could set up a masterpage. Add parameters to a route. As is said this example is just a simple one to show something. If you have further questions don't hesitate to ask me and don't forget to have a look at the documentation which explains it much more in detail.

--- FURTHER EXAMPLE / INFORMATION ---

Some might ask why Pvik uses classes for the definition of a database. This gives you the possibilty to add function to you ModelTable and your Model:

<?php
class AuthorsModelTable extends ModelTable {
    //  ... //

    // returns a AuthorModel or null by its name
    public function LoadAuthorByFullname($Firstname, $Lastname){
        // this variable indicates if all authors already loaded
        // into the cache
        if($this->LoadedAll){
            // if everything is loaded this functions doesn't run a sql
            // instead it loads the authors from the cache
            $Authors = $this->LoadAll();
            $Author = $Authors->FilterEquals('Firstname', $Firstname)
                   ->FilterEquals('Lastname', $Lastname)
                   ->GetFirst();
            return $Author;
        }
        else {
            // we have to run a sql statement
            $Query = new Query('Authors');
            $Query->SetConditions('WHERE Authors.Firstname = "%s" AND Authors.Lastname = "%s"');
            $Query->AddParameter($Firstname);
            $Query->AddParameter($Lastname);
            $Author = $Query->SelectSingle();
            return $Author;
        }
    }
}
class AuthorModel extends Model {
    // ... //

    public function GetFullname(){
        return $this->Firstname . ' ' . $this->Lastname;
    }
}

A new controller:

class AuthorsController extends Controller {
    public function Author(){
        // get parameters from the url
        $Firstname = $this->Parameters->Get('firstname');
        $Lastname = $this->Parameters->Get('lastname');
        // call our new function
       $Author = ModelTable::Get('Authors')->LoadAuthorByFullname($Firstname, $Lastname);
       if($Author!=null){
            $this->ViewData->Set('Author', $Author);
            $this->ExecuteView();
       }
       else {
           // redirects to the root page
           $this->RedirectToPath('~/');
       }
   }
}
?>

Our very simple view:

 <!DOCTYPE html>
<html>
   <head>
      <title>Author</title>
   </head>
   <body>
      <?php
           // getting the data from the controller
           $Author = $this->ViewData->Get('Author');
           /* @var $Author AuthorModel */

           // we just display the fullname
           echo $Author->GetFullname();
      ?>
    </body>
</html>

And again we need to register the route in the config:

self::$Config['Routes'] = array (
    // ... //
    array ('Url' => '/author/{firstname}/{lastname}/', 'Controller' => 'Authors', 'Action' => 'Authors')
);

Now we can call our website via example.org/author/william/shakespear/

Documentation

Github

\$\endgroup\$
10
  • \$\begingroup\$ You'll have to move the code you want reviewed here. \$\endgroup\$
    – yannis
    Commented Apr 11, 2012 at 0:17
  • \$\begingroup\$ It is more a project review than a code review. And I think it wouldn't make sense to move all the code (54 files) here. As I said in the first sentences, I'm not sure if this here is the right place and I apologize if it isn't but maybe you could suggest a better place? \$\endgroup\$ Commented Apr 11, 2012 at 0:30
  • \$\begingroup\$ You don't have to move all the code, you could start by moving some of the more essential parts of it. This is the right place for your question, but it's a bit unreasonable to expect people to go to your repository and review 54 files. You can always post more than one questions, no need to have all the code in one... \$\endgroup\$
    – yannis
    Commented Apr 11, 2012 at 0:33
  • \$\begingroup\$ Ok, that makes more sense. Do you think the documentation -> roccosportal.com/how-to is better? Than I'll move parts from it to here. It's just a complex system and it is hard to explain it without mention other parts of the framework. \$\endgroup\$ Commented Apr 11, 2012 at 0:40
  • 1
    \$\begingroup\$ Yes, this is good now, +1. \$\endgroup\$
    – Paul
    Commented Apr 13, 2012 at 10:40

1 Answer 1

2
\$\begingroup\$

Do not force developers to hand-code ModelTable subclasses (it is error-prone, monotonous, and time-consuming). Use PDO to automatically create base classes for all selected tables (entities) in the system. You could develop a web UI for table selection, column selection, and so forth. You could also generate "List of Value" view objects that are derived from foreign-key relationships.

As a developer, if I wanted to change an entity's behaviour, I would subclcass it then use polymorphism to inject custom code.

The relationship becomes:

ModelTable -> AuthorsGeneratedModelTable -> AuthorsModelTable

The AuthorsModelTable could be optional.

If you are looking to create a framework that generates a web site for editing code tables, I suggest researching existing solutions.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.