Welcome Guest, Not a member yet? Register   Sign In
Oobleck - A patterned approach to dealing with forms and databases in CI controllers
#1

[eluser]webthink[/eluser]
Explanation with examples can be found <a href="http://webthink.ca/oobleck">Here</a>

During Webthink's last major project we noticed that a lot of time was spent writing controller code to deal with forms and and database interactivity. It seemed we were writing a lot of lines to accomplish the same basic actions with only minor variance from one controller to the next. Lists of form/db fields tended to be written on average about 4 times. a)to set up fields for validation b)to set up rules for validation c)to assign data from the db to an array to be used for defaulting forms d)to assign data from forms to an array to be used to write to the db. In addition to this a lot of procedural logic used to ferry data from the form to the db and vice-versa was repeated.

At it's core a controller is designed to handle control flow logic and business logic so we came up with an approach that seperates this from a lot of the repetative grunt work tasks that were rapidly filling up our controllers. The approach is two pronged: It relies on a pattern by which you organize your controller and a library to abstract some of the control code.

Keep in mind though that it really is just an approach. It's meant to be altered to fit your needs. You could theoretically use as little or as much of it as you please or simply give it a look over and implement something similar but better suited to your needs.

Some credit for inspiration at least has to be given to Michael Wales and his <a href="http://www.michaelwales.com/2007/10/erkana-codeigniter-authorization-library/">ErkanaAuth project.</a> We looked at it, liked it, and then decided not to use it. There in lies the beauty of it though. It's less of package and more of a suggested approach so when we looked over it we thought 'It's simple, it's elegant and there's really nothing to it. Let's write our own'. My hope is that Oobleck gets treated in much the same way. It's not a packaged solution it's more of a design philosphy from which people are free to take what they like. To the best of my ability I've designed it to be as non-invasive as possible but it is a rethink to the way we code controllers so requires a certain amount of buy in.

Additionally the motivation to abstract a lot of our controller code came after we did the same for our models. For that we adopted <a href="http://codeigniter.com/wiki/ActiveRecord_Class_Mod/">CoolIce's Active Record ORM Library</a> and in doing so completely stripped down our models.

The code is still in Beta so We'll be fixing it up as we go along. As we continue to develop and use Oobleck more for our own projects I hope to develop more flexibility into it so that it can handle more non standard scenarios. With one exception there won't be any feature development only development in expanding it's flexibility. That exception is of course a form generator. It seems a naturual fit and webthink->Andrew who does much of our front end implementation has a lot of experience with these sort of things. Whatever we do come up with will have to hang off of Oobleck but more than that it will have follow the same principles and be fully overridable and non-invasive.

Why Oobleck? Well mostly because "A patterned and abstracted approach to interfacing user input forms and database interaction within CodeIgniter controllers" doesn't lend itself very easily to a clever acronym. We needed a made up word. Fortunately <a href="http://en.wikipedia.org/wiki/Oobleck">Dr. Suess provided us with a great one</a>

Hope it can be of use to someone.

webthink->Julian
#2

[eluser]xwero[/eluser]
From your post i see there is gone a lot of thought into this, what a great way to introduce yourself on the forum, glad to have you here.

Glancing over the code it seems to me like a good library to handle forms where the add fields are identical to the update fields and where you have simple database actions. It is possible to have different fields if you add a parameter to the _set_fields method. But i think once you have to do multiple queries for one action the library is too strict, not?

I would love to see some complex examples, if you find the time.
#3

[eluser]webthink[/eluser]
Hi xwero,
You're right. The biggest challenge was coming up with a way to handle cases where fields are not mapped identically between form and table. That's why I implemented the dynamically named functions to go in your controller: set_additional_fields[TABLE_NAME]_[ACTION]() and _process_to_db_[FIELD_NAME]() the former sets any fields that aren't present in the form on a per table basis and the latter allows you to process individual fields prior to insert/update. If you look at the example for the user registration form you can see that I'm updating two tables and for each I'm adding a additional fields for each table and doing some pass through processing on some individual fields.
If you can think of a non-standard example where this might not be enough I'd like to know because I'd like to build in flexibility where ever possible.
If you mean how would I deal with controllers where there are multiple forms each with a unique set of fields that's something I had planned on building support for. I'll let you know when I've got something.

Thanks
#4

[eluser]xwero[/eluser]
One scenario i'm thinking about is : you have an order by field but if there are no items in the database you don't want to display the field and then you also don't need to validate it but after the first item is added the order by field is present. So there would have to be an isset check somewhere.

The second scenario is : you have blog items where the titles for the permanent urls. You have one table where you store the blog post data and another to store the urls for fast access. In order to do this you need to have at least two queries to make it possible to manipulate the data.

If it's possible i would love to see the code.
#5

[eluser]abmcr[/eluser]
Very interest..... and a Upload Field ..... have you idea to develop it? Ciao and thank you for sharing the code
#6

[eluser]webthink[/eluser]
Interesting. I'm glad you've got me thinking about this stuff as if the library is too tightly coupled to only standard ways of manipulating data then it's not as useful. Fortunately I think your examples can be handled within the controller.
If in your _set_fields method you had something like.

Code:
$this->fields = array(
        'name'                            => array(
                                        'nice_name'            => 'Name',
                                        'validation'        => 'trim|required|strip_tags|xss_check',
                                        'field_type'        => TEXT_FIELD,
                                        'db_field'            => 'TRUE'
                                        ),
        'description'                    => array(
                                        'nice_name'            => 'Description',
                                        'validation'        => 'trim|required|strip_tags|xss_clean',
                                        'field_type'        => TEXTAREA_FIELD,
                                        'db_field'            => 'TRUE'
                                        ),
        );
        if ($this->my_model->count() > 0)
        {
                    $this->fields ['order_by']                => array(
                                        'nice_name'            => 'Order by',
                                        'validation'        => 'trim|required|strip_tags|xss_check',
                                        'field_type'        => TEXT_FIELD,
                                        'db_field'            => 'TRUE'
                                        );
        }

That would make the order_by field conditional.

For your second example it's possible to edit more than one table at a time.
In my register example I insert records into both the users and profiles table like this
Code:
$this->oobleck->fill_table_from_form(CREATE,'user');
$this->oobleck->fill_table_from_form(CREATE,'profile');

The one thing I hadn't thought about though is how a standard model may handle being sent an associative array that contained fields that weren't actually part of the table being updated. I'm using the modified active record ORM and fortunately it just ignores any additional fields. It would probably help if I built in support for mapping the form fields to the appropriate table fields so that instead of 'db_field' => TRUE in your fields array you might have something more like 'db_field' => 'table_name.field_name'

Thanks for helping me think about things a bit more.
#7

[eluser]webthink[/eluser]
Hi abmcr,
Upload is a bit tricky because there isn't just a form->db interface to worry about. You've also got to handle the server side storage/processing of the file.
What you could do is handle all of that within one of the _set_additional_values_[TABLE_NAME]_[ACTION] functions which are called automatically. That way you do everything you need to do with the physical files according to your own set up. and then set $additional_values ['file_path'] or whatever you want to be inserted into the db. The fill_db_from_form() library method will automatically check to see if this method exists in your controller and then use whatever values are returned from it to update/insert into the db.
#8

[eluser]xwero[/eluser]
[quote author="webthink" date="1203958930"]
For your second example it's possible to edit more than one table at a time.
In my register example I insert records into both the users and profiles table like this
Code:
$this->oobleck->fill_table_from_form(CREATE,'user');
$this->oobleck->fill_table_from_form(CREATE,'profile');
[/quote]
I was sure there was a way to do the first scenario without too much trouble But with the second scenario there is an additional factor. Because the url is part of another table where other urls are gathered as well it's possible the id in the url table isn't the same as the id in the blog table. I don't want to create another table so i add a ref_id field to the url table but to fill that ref_id field you need to know the insert_id so that part will be
Code:
$this->oobleck->fill_table_from_form(CREATE,'user');
$insert_id = $this->db->insert_id();
How can you add the insert_id variable to the url insert? If i understand your code for the additional fields, it only looks for a function in the controller.
#9

[eluser]webthink[/eluser]
If you're talking about using the insert id from the first table as a foriegn key in the second table that is what I'm doing. It isn't obvious but because my model automatically holds the id after you create the record all I had to do was
Code:
function _set_additional_values_profile_create()
{
    $additional_values = array();
    $additional_values['user_id'] = $this->user->id;
    return $additional_values;
}

My user model is set up to hold the id after insert so when I need to reference it in my controller I can use $this->user->id This allows me to then add it as an additional field in my profile table (profiles.user_id). If you didn't have your model set up to automatically store the id then I'd do as you suggest which might look something like:
Code:
$this->oobleck->fill_table_from_form(CREATE,'table_1');
$this->table_1_id = $this->table_1_model->get_id();

and then you could have something like:

Code:
function _set_additional_values_table_2_create()
{
    $additional_values = array();
    $additional_values['user_id'] = $this->table_1_id;
    return $additional_values;
}

I hope I've understood the requirement.
#10

[eluser]xwero[/eluser]
Ok i guess it's a bit too much for me to digest at once Smile I think you put the additional values into a function because then you can abstract it or is there another reason? Maybe you could add a method to deal with the additional values in a more intuitive way for not so smart people like me Wink

Maybe you should add a prefix to you constants so they don't collide with previously set constants.




Theme © iAndrew 2016 - Forum software by © MyBB