Ban Ctrl+C in your development
You are merrily coding away, throwing a bunch of text into files when you want to create some code (using symfony, naturally) to extract records from your database to display on the page. Sooooo, you pop the following into an action:
$c = new Criteria(); $c->add(SomeModelPeer::COLUMN, $value); $this->records = SomeModelPeer::doSelect($c);
Carrying on, new feature, new feature and then you realise that another action in your awesome code needs to do the exact same thing and extract records from the database. The steps tend to be: Highlight previous code chunk -> Hit Ctrl+C -> Go to location that needs it and Ctrl+V.
Obliviously you carry on. Things work as you want, without realising that you have left yourself a lovely little grenade called "Maintenance Nightmare" right there. Let me paint a scenario....
A week later, after having a development discussion with the other members of Dev Awesomness, you realise that the table in your database needs to be altered schema-wise. Little do you know that this change now impacts that little piece of code you wrote and liberally copy/pasted all over the place. You fix the first location you use that code, but another bug pops its ugly head and you fix that one. And keep hitting wall after wall of errors because of all the 17 other places you forgot about that you pasted that same code chunk into. I did say "Nightmare" right?
The alternative? symfony provides you model classes you can use to refactor code into for commonly used functions. So instead of inserting that code directly into an action you could instead move it inside the SomeModelPeer class:
class SomeModelPeer extends BaseSomeModelPeer { public static function getRecordsByValue($value) { $c = new Criteria(); $c->add(SomeModelPeer::COLUMN, $value); $records = SomeModelPeer::doSelect($c); return $records; } }
And in your action, your copy/pasted chunks of code turn into:
$this->records = SomeModelPeer:: getRecordsByValue($value);
Wow. Now everytime you have a change to make to HOW those records are retrieved you edit one location and it will automatically affect all 17 locations that you need it.
If there any "veteran" symfony developers reading this, your response will probably be along the lines of "Well, duh!", but give me a moment here. That's a very basic example. How often do you render forms from an sfForm object? Does it look something like this?
<form action="<?php echo url_for('module/action')?>"> <ul> <?php echo $address_form['hidden_id']->render() ?> <?php echo $address_form['_csrf_token']->render() ?> <li> <?php echo $address_form['field1']->renderError() ?> <?php echo $address_form['field1']->renderLabel() ?> <?php echo $address_form['field1']->render() ?> </li> <li> <?php echo $address_form['field2']->renderError() ?> <?php echo $address_form['field2']->renderLabel() ?> <?php echo $address_form['field2']->render() ?> </li> </ul> <input type="submit" value="Save"/> </form>
And the next time you have to render a form? Copy and paste FTW!!! Or is it? Why not create a global partial that looks like this?
<form action="<?php echo url_for($module.'/'.$action) ?>" method="POST"> <ul> <?php foreach ($form->getWidgetSchema()->getFields() as $widget_name=>$widget_element): ?> <?php if ($form[$widget_name]->isHidden()): ?> <?php echo $form[$widget_name]->render() ?> <?php else: ?> <li><?php echo $form[$widget_name]->renderRow() ?></li> <?php endif; ?> <?php endforeach; ?> </ul> <input type="submit" value="<?php echo $submit_value ?>"/> </form>
Then on a template you need to display a form, any form, no matter what, you can just use:
<?php include_partial('global/renderForm', array( "form"=>$form_object, "module"=>'module_to_submit_to', "action"=>'action_to_submit_to', "submit_value"=>'Text for submit button' )); ?>
The advantages are huge! Firstly it saves time. Secondly, it improves consistency. If you want to change the look of the forms that get rendered you have one file to edit to alter their structure instead of all 129 different forms rendered all over the place in your application.
There are just so many ways to make re-use the primary aspect of your development. Every piece of code you wrap in an easily re-usable format is another piece of code you never need to write ever again. Here at SYNAQ we have even gone so far as to create a specialised SVN repository to store commonly re-used function, symfony helpers, etc which we incorporate into our projects using the svn:externals property. This means that we can change that particular piece of code once and it will naturally spread over all the applications that use it.
Ban Ctrl+C in your development. Refactoring is the key to speeding development time and helping to reduce your maintenance overhead in future. Remember, change is the only constant.