Please recommend me a PHP framework!

Atheus

Diamond Member
Jun 7, 2005
7,313
2
0
Hi all,

Recently I've been trying to make Wordpress or Drupal fit whatever site I'm building as having those core elements already in place makes things so much easier, but now I have a site to build which is totally unsuitable for WP or Drupal. It's more of a web-based application which doesn't need to deal with any text editing or templates or anything like that - what I need is a simple and easy to learn PHP base framework with components I can pull into my application.

I was immediately drawn to CodeIgniter because of its simplicity and performance and support, but the features I'm particularly interested in are user authentication, user managements, roles, ACLs, sophisticated file mangement and file permissions for users... and these just happen to be some of the features CodeIgniter doesn't have...

So what should I be looking at? The full-on approach of Zend or Cake or is there something a little more basic which has the required modules?

Any help appreciated :)
 
Last edited:

hooflung

Golden Member
Dec 31, 2004
1,190
1
0
I think you should be looking at CodeIgniter. I work with it on a daily basis and there are plenty of 3rd party libraries that you can use.

http://github.com/benedmunds/CodeIgniter-Ion-Auth

Also, you should be using a Modular Separation library with any of your code:

http://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc

If you want to do a CMS then I suggest you look at PyroCMS written in CodeIgniter using both of the code pieces above:

http://pyrocms.com/

Zend and Cake are just way too fat for my tastes. Kohana and Symphony are your other choices. Try CI with those 2 Libraries. You can even try my CRUD Library if you want:

http://bitbucket.org/michaelhowell/crudform

2 website blogs you'll want to visit:

http://www.weblee.co.uk/
http://philsturgeon.co.uk/

Also, check out the IRC channels, they are active. #codeigniter and #pyrocms on Freenode.
 

Atheus

Diamond Member
Jun 7, 2005
7,313
2
0
Thanks! Might hop on #codeigniter and see what they can tell me about the auth modules.

If you want to do a CMS then I suggest you look at PyroCMS written in CodeIgniter using both of the code pieces above

Nah no CMS this time - that's why I'm not going with my usual Wordpress/Drupal... it's a sort of... storage and distribution system... it's under NDA...

Any more suggestions anyone? Zend and Cake look bloated to me too but some ppl swear by them.
 

hooflung

Golden Member
Dec 31, 2004
1,190
1
0
Zend and Cake are bloated. They try to be an answer to RoR but they adopted things that the RoR have been weeding out of the Rails stack for years. Symphony, CodeIgniter and Kohana do things their way.
 

Ka0t1x

Golden Member
Jan 23, 2004
1,724
0
71
afaik that's an Editor. Editor != Framework

CodeIgniter has been on my todo list for a while.. It'd be great if you could respond back in about a week if you start using it.
 

sourceninja

Diamond Member
Mar 8, 2005
8,805
65
91
I really should explore using a framework. Every time I sit down to do it however I discover how freaking difficult it is to wrap the framework around our insanely horrible database. I don't see too many advantages of frameworks without a database that fits easily into a MVC design.

We didn't build the database, we can't modify the database's design, but we have to use it. It's not that I don't want to explore frameworks, it's that the effort to cram this thing into a framework is way more then just continuing to do everything 'from scratch'.
 

hooflung

Golden Member
Dec 31, 2004
1,190
1
0
I really should explore using a framework. Every time I sit down to do it however I discover how freaking difficult it is to wrap the framework around our insanely horrible database. I don't see too many advantages of frameworks without a database that fits easily into a MVC design.

We didn't build the database, we can't modify the database's design, but we have to use it. It's not that I don't want to explore frameworks, it's that the effort to cram this thing into a framework is way more then just continuing to do everything 'from scratch'.

I think that is a false assumption. Anything you do by hand can be done easier in a framework if you know how to do object oriented coding in php5 properly.

For instance my CRUDForm library exists to DRY out controllers. It isn't perfectly DRY but its getting closer with each revision. Here is an example for CodeIgniter running on top of PHP5:

Code:
CREATE TABLE `products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `vendor_id` int(10) NOT NULL,
  `product_type_id` int(10) NOT NULL,
  `gallery_id` int(10) NOT NULL,
  `item` varchar(150) NOT NULL,
  `is_active` tinyint(1) NOT NULL DEFAULT '0',
  `description` text NOT NULL,
  `created_on` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_on` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

A child class of CRUDForm would hold metadata that explains what models to load, tables to expect and what views to send them too and it would look like this:

PHP:
<?php if( ! defined('BASEPATH')) exit ('No direct script access allowed');

class Products extends CRUDForm {

    /**
    | Page name that is passed into the parent controller. The Data array in
    |   class variable array contains elements that are array. These arrays represent tables
    |   in the database. Non array elements in the data array are for logic and view
    |   workflow.
    |
    */
    protected $schema = array(
        'page_url' => 'products',
        'model' => 'Products_m',
        'data' => array(
            'id' => array('value' => '', 'type' => 'int'),
            'vendor_id' => array('value' => '', 'type' => 'int'),
            'gallery_id' => array('value' => '', 'type' => 'int'),
            'product_type_id' => array('value' => '', 'type' => 'int'),
            'item' => array('value' => '', 'type' => 'char'),
            'is_active' => array('value' => 0, 'type' => 'bool'),
            'description' => array('value' => '', 'type' => 'char'),
            'page' => 'products', //body tag id
            'message' => '', //this is specifically for the view
            'action' => 'create' //this is specifically for the controller
            ),
        'views' => array('edit' => 'admin/products/edit', 'listing' => 'admin/products/listing'
            )
        );

    function __construct()
    {   
        parent::__construct();

        $this->load->model('Vendors_m');
        $this->load->model('Product_types_m');
        $this->load->model('Image_gallery_m');

        if( ! $vendors = $this->Vendors_m->get()) {
            $this->session->set_flashdata('message', 'Before you add products you must at least have 1 vendor available.');
            redirect('/admin');
        }

        if( ! $types = $this->Product_types_m->get()) {
            $this->session->set_flashdata('message', 'Before you add products you must at least have 1 product type available.');
            redirect('/admin');
        }

        if( ! $galleries = $this->Image_gallery_m->get()) {
            $this->session->set_flashdata('message', 'Before you add products you must at least have 1 picture uploaded into a gallery.');
            redirect('/admin');
        }

        foreach($vendors as $row) {
            $this->schema['data']['dropdown']['vendors'][$row->id] = $row->company;
        }

        foreach($types as $row) {
            $this->schema['data']['dropdown']['types'][$row->id] = $row->type;
        }

        foreach($galleries as $row) {
            $this->schema['data']['dropdown']['galleries'][$row->id] = $row->name;
        }
    }
}


The model, which is child of a class ( MY_Model ) that extends the CI's model class and has abstract DB calls based on CodeIgniter's own ActiveRecord library. You only need metadata in the form of a protected class variable ;)

PHP:
<?php if( ! defined('BASEPATH')) exit ('No direct script access allowed');

class Products_m extends MY_Model {


    protected $model_schema = array (
        'table' => 'products',
        'join' => array(
            'vendors' => "products.vendor_id = vendors.id",
            'product_types' => 'products.product_type_id = product_types.id',
            ),
        'select' => 'products.id, products.vendor_id, products.item, products.is_active, products.picture, products.description, product_types.type, vendors.company'
    );

    function __construct() {
        parent::__construct();

    }

    function get_dropdown() {
        $this->model_schema['select'] = 'products.id, products.item';

        return parent::get();
    }

    public function is_active($id = '') {
        $this->model_schema['select'] = 'id';

        $field = 'is_active';

        return parent::bool_check($id, $field);
    }

    public function get_for_public() {
        $this->model_schema['where'] = array('products.is_active' => '1');
        $this->model_schema['order_by'] = 'product_type_id';

        return parent::get();
    }
}

The Edit View would look like this:

PHP:
<?php $this->load->view('admin/admin_header'); ?>

<?php
    $hidden = array(
        'id' => $id['value'],
        'action' => $action);

    $form['item'] = array(
        'name' => 'item',
        'id' => 'item',
        'maxlength' => '50',
        'size' => '50',
        'value' => htmlspecialchars_decode($item['value']));

    $form['is_active'] = array(
        'name' => 'is_active',
        'id' => 'is_active',
        'value' => 'yes',
        'checked' => process_checkbox($is_active['value']));

    $form['description'] = array(
        'name' => 'description',
        'id' => 'description',
        'rows' => '7',
        'cols' => '50',
        'value' => htmlspecialchars_decode($description['value']));

?>

            <div id="content" class="grid_16">

                    <h1>Product Edit Page</h1>

                    <div id="error"><?php
                        if($message) {
                            echo $message;
                        }
                        elseif($this->session->flashdata('message')) {
                            echo $this->session->flashdata('message');
                        }
                    ?></div>

                    <p class="infoBox">Please enter the following information.</p>

                    <?php echo form_open('products/edit'); ?>

                    <?php echo form_hidden($hidden); ?>

                    <div class="row1"><label for="vendor">Vendor: </label><?php echo form_dropdown('type_id', $dropdown['vendors'], $vendor_id['value']) ?></div>

                    <div class="row2"><label for="type">Product Type: </label><?php echo form_dropdown('status_id', $dropdown['types'], $product_type_id['value']) ?></div>

                    <div class="row1"><label for="gallery">Image Gallery: </label><?php echo form_dropdown('status_id', $dropdown['galleries'], $gallery_id['value']) ?></div>

                    <div class="row2"><label for="is_active">Check to Activate Item: <em>(Required)</em></label><?php echo form_checkbox($form['is_active']) ?></div>

                    <div class="row1"><label for="item">Item: <em>(Required)</em></label><?php echo form_input($form['item']); ?></div>

                    <div class="row2"><label for="description">Description: <em>(Required)</em></label><?php echo form_textarea($form['description']); ?></div>

                    <p class="submit"><input type="submit" name="submit" value="Save Record" class="save" /></p>

                    <?php echo form_close(); ?>

                    <?php echo anchor('/admin/index', 'Back to admin'); ?>

            </div>

<?php $this->load->view('admin/admin_footer'); ?>

There are some assumptions you must consider. The CRUDForm is essentially an extended CodeIgniter controller. Thus the name of the Class will show up in the URL in segment 1.

example.com/products

The methods will be segment 2

example.com/products/edit

The query data, in this case the ID because that is what my edit method takes into account, is segment 3

example.com/products/edit/1

You could wrap just about any horrible schema'ed database because once CRUDForm, or your own custom variation of it, would only need Metadata supplied to it.

You go even further when you use a Modular Separation Library because instead of just having a /controllers directory inside your CI's application directory you would have a /modules directory. Each directory under that would be a module such as application/modules/products which would have its own models/views/controllers/config directories.

This way you can keep top level database objects like Products or Employees separate so you could work on one custom module at a time. If you need something more than what a custom controller like CRUDForm would offer, and I sure have those myself such as image asset uploader, you can just extend the CI controller and write whatever custom code, and still have the Database model's methods and you can even extend the Model's child class for custom db needs.

All without going too far off the reservation of what a vanilla CI install does. All you need is CRUDForm and the modular separation library to get started. Or, to write your own CRUD enabled DRY controller. Or fork mine (yay open source).
 
Last edited:

sourceninja

Diamond Member
Mar 8, 2005
8,805
65
91
I guess what I'm saying is at this point I've basically hand written enough tools, classes, and 'stock code blocks' that it takes me minutes to get my jobs done without a framework. Everytime I've looked at using a framework it seemed like a LOT of work to get off the ground. Our database has more tables then I actually know. I'm only familiar with about 50 of them or so, but to switch to a framework would require me to get with the other developers, decided on a framework, then start a massive project to figure out how to write all the models.

This database is horrid, there is no real easy way to say 1 to N. Sometimes it's "use this value if it exists, but if not use this value, but if the first value does not exist, and the second one does, but this third is null, use this computed value from this stored procedure. Other's require very strict editing of multiple tables to make a simple insert. Sadly, changing any of this would break the proprietary super important business application we pay tens of thousands a year for. Also, it is oracle, and there used to be a few issues with oracle and many frameworks including CI. Not sure if that is still the case or not.

So now I just grab the class that handles it I wrote years ago and boom it's fine. To switch would require tons of effort trying to standardize everything we do so it all fits nicely into a framework.

Should it be done? I think so. Will it be done? Sadly, I doubt it (unless mandated by our superiors).

Hell it was a nightmare to get the developers to switch from DB to PDO. Even that required a 6 month debate on the merits of ADODB, PDO, and MDB2.
 
Last edited:

sourceninja

Diamond Member
Mar 8, 2005
8,805
65
91
Now for some funny information, saying I can't do something is usually enough to get me to actually do it.

So I just spent the last 30 minutes screwing with CI seeing how I might be able to get our newest project using it.
 

hooflung

Golden Member
Dec 31, 2004
1,190
1
0
PDO is not officially supported by CI like the direct php drivers for mysql, postgresql, sqlite 2 etc.

There are 3rd party drivers to bridge PDO and CI's Active Record Library for sure. I've not had any luck with them but that was when my primary app was hosted on a Win2k8 server via IIS7 and FastCGI.

Should work well on apache and linux. Also, remember any php class could be loaded as a library.

Put it in the applications\libraries folder while adhering to CI's naming convention <filename>.php = class name.

application\libraries\filename.php

Then you just load $this->load->library('Filename');

Then you can use $this->Filename->method();

So you can shoehorn legacy code into a framework.

The kicker is if you want to use CI's libraries inside your custom library you would either do the official way:

PHP:
$CI =& get_instance();

$CI->load->helper('url');
$CI->load->library('session');
$CI->config->item('base_url');

$CI->session->set_userdata(array('logged_in' => TRUE));

OR you can do it the PHP5 way, which uses magic methods ( the holy grail of php5's OOP features to be sure ) which allows you to use $this->session->set_userdata() like a native CI class.

PHP:
function __get($var)
{
     static $ci;
     isset($ci) OR $ci =& get_instance();
      return $ci->$var;
}
 
Last edited:

Atheus

Diamond Member
Jun 7, 2005
7,313
2
0
Thanks all - any more info on Auth with CI or other platforms still much appreciated.

It'd be great if you could respond back in about a week if you start using it.

Will definately bump the thread when the project starts - maybe in a week or two. Currently CI is top of my list.
 

sourceninja

Diamond Member
Mar 8, 2005
8,805
65
91
I had forgotten about this thread.

We spent about 5 days playing with CI. We found it very nice, however, like everything else it still doesn't fit nicely around the 3,000 table database and hundreds of php objects we have to work with. Besides just having a model, controller, and view (which we do already) most everything else was just fluff that would be ignored. We already have a working in house MVC setup and a query builder for CRUD operations (although 95&#37; of our queries are too complicated for that class to handle or just use procedures to place the data where it belongs.) that wrappers around PDO.

I was however impressed enough with CI that I will be using it for a side project I was hired to write. It will fit perfectly into the solution for their problem. I think it is the most flexible of the frameworks I've looked at (Zend, Symphony, Cake, etc), I just wish I could fit it around our database.

What good did come out of it however was a review of coding standards (and revising them to meet more php 5.3 features).

We are looking at using CI to create a REST api for our applications to use to talk to our database. This is a ground up fresh project that will be using no existing code. This is of course providing php wins out in the language. A few guys think we should go the java route.

On a side note, I really wish I could find a nice PHP ORM solution that would work well with our database. I tried doctrine and propel but both of them can't properly reverse engineer (No way I'm going to try to create the schema by hand) our database. This is because all of the tables are spread out into multiple schemas and the only schema their tools can seem to reverse engineer is the primary schema for the user you log in with.
 

hooflung

Golden Member
Dec 31, 2004
1,190
1
0
I am not sure why anyone who has a working PDO solution for a large complicated data base would want to champion JAVA as the language for a REST API.

http://net.tutsplus.com/tutorials/php/working-with-restful-services-in-codeigniter-2/

Check out that link for a CI rest server install. And if you need something more barebones...

http://philsturgeon.co.uk/news/2010/04/tiny-rest-framework

buy that for 7 dollars.

Phil is a great programmer, gives back to the CI community and has helped me out of a lot of pinches in IRC. Also, if you need an ORM I really think you should build one if you cannot figure out how to get the latest <latest> LATEST version of doctrine to work. If it has been a while since you tried doctrine look at it again. A lot of things has changed.

But when all else fails move into PHP 5.3's domain and start using namespaces and class interfaces to build your own ORM. It wouldn't be that hard. Hell I even wrote a micro ORM the other day for a browser based game idea I had. You just have to figure out if you need a Data Mapper Pattern or Active Record Pattern and if you want your end product to be a singleton or not.