Ultra-lightweight Scriptaculous Horizontal Accordion 
After trying this one out and having very little success on anything but the most simplest of pages, I decided that I had to go it alone...

And what I got was a rock solid horizontal accordion in about 30 minutes and less than 100 lines of code - including CSS, HTML and JavaScript!

So here it is:

<div class="acc_container">
<div class="acc_handle" id="handle_1">H1</div>
<div class="acc_panel" id="panel_1">Content 1</div>
<div class="acc_handle">H2</div>
<div class="acc_panel">Content 2</div>
<div class="acc_handle">H3</div>
<div class="acc_panel">Content 3</div>
</div>

<style>
.acc_container{
height: 500px;
min-height: 500px;
}

.acc_handle{
float: left;
width: 55px;
height: 500px;
min-height: 500px;
background-color: #dddddd;
cursor: pointer;
border: solid 1px #666666;
font-size: 9px;
}

.acc_handle:hover{
background-color: #eeeeee;
}

.acc_handle_active{
float: left;
width: 55px;
height: 500px;
min-height: 500px;
cursor: pointer;
border: solid 1px #66bb66;
font-size: 9px;
background-color: #ddeedd;
}

.acc_panel{
float: left;
}
</style>
<script>
function acc_open(event){
var element = Event.element(event);
x= get_nextsibling(element);
$$('.acc_panel').each(function (el) {
if (el != x && el.style.display != 'none'){
new Effect.Squish(el);
}
});
$$('.acc_handle_active').each(function (el) {
el.className='acc_handle';
});
if (x.style.display == 'none'){
new Effect.Grow(x);
element.className='acc_handle_active';
}
}

function get_nextsibling(n){
x=n.nextSibling;
while (x.nodeType!=1){
x=x.nextSibling;
}
return x;
}
Event.observe(window,'load',function(){
$$('.acc_handle').each(function (el) {
el.observe('click', acc_open);
});
$$('.acc_panel').each(function (el) {
el.style.display = 'none';
});
new Effect.Grow($('panel_1'));
$('handle_1').className='acc_handle_active';
});

</script>


Of course, you can style this with active and hover classes etc...
  |  [ 0 trackbacks ]   |  related link
Symfony propel select MAX() 
I know it's simple but it's one of those things you need to do often but not often enough to commit the technique to memory. So this is a code snippet for those times...
//get most recent sales date
$connection = Propel::getConnection();
$c = new Criteria();
$query = 'SELECT MAX(%s) AS max FROM %s';
$query = sprintf($query, PurchasePeer::FINISH_DATE,PurchasePeer::TABLE_NAME);
$statement = $connection->prepareStatement($query);
$resultset = $statement->executeQuery();
$resultset->next();
$this->sales_date = strtotime($resultset->get('max'));

  |  [ 0 trackbacks ]   |  related link
Upload from one Symfony backend to another domain frontend 
I have a backend for 7 domains sitting on its own domain - with all 8 domains running inside the one Symfony installation.

The problem we faced was how to upload files inside an FCKedtor in the backend domain and have the frontend domains pick up the files without exposing the backend domain in the image tag SRC attribute.

For some of the sites we did this on an ad hoc basis using readfile within the view - but this was for images uploaded into the database, so we knew the record ID from the URL.

When using FCKedit we don;t know anything about the files until we pull the HTML out of the database and parse it.

After much deliberation the solution was to use a filter...

class backendAssetsFilter extends sfFilter
{
public function execute ($filterChain)
{

// execute next filter
$filterChain->execute();

//sfLoader::loadHelpers(array('Url'));
$local_url = "/uploads/assets/";
$readfile = '/home/asset?file=';
$response = $this->getContext()->getResponse();
$response->setContent(str_ireplace($local_url, $readfile, $response->getContent()));


}
}


This filter simply replaces the /uploads/assets string with a URL that performs the readfile. As the URL can contain subfolder names, the filter works for /uploads/assets/images as well as /uploads/assets/flash etc.

And while it is a bit of a hit on the server, it works across the whole domain for all HTML content managed by FCKedit., which is worth it :)
  |  [ 0 trackbacks ]   |  related link
Using view helpers from a controller revisited 
Damn, I should have realised you can call url_for() from a controller - you just have to load the helper first!

sfLoader::loadHelpers(array('I18N', 'Url'));

url_for('@somerouting')

  |  [ 0 trackbacks ]   |  related link
JavaScript dupicate table row inside a table 
There are a lot of tips 'out there' on how to add a table row to the end of a table, but I found an elegant way of duplicating a table row in the middle of a table...

function addRow(button)
{
btn_row = button.parentNode.parentNode;
x=btn_row.previousSibling;
while (x.nodeType!=1){
x=x.previousSibling;
}
row = x.cloneNode(true);
btn_row.parentNode.insertBefore(row,btn_row);
}

Then you can trigger it from a table cell using:

<input type="button" onclick="addRow(this);" value="+" />


Note the while() loop filters out white space nodes in Firefox (naughty Firefox).



  |  [ 0 trackbacks ]   |  related link
Using view helpers from a controller in Symfony 1.0 
I wanted to use url_for() in a controller for a search and replace operation. It turns out the URL helper is a wrapper for a controller function!

sfContext::getInstance()->getController()->genUrl("click here","@route?id_id=".$id);

too easy!
  |  [ 0 trackbacks ]   |  related link
Prototype radio button validation 
Have a required radio button and want to ensure one option is checked? Here's a one-liner for your troubles...

checked = $$('input:checked[type="radio"][name="reward"]').pluck('value').length

Assuming your radio buttons have the name="reward" attribute you can now do the following:

if (!checked ){
alert('select something!');
}


That's it!

PS: This was working great for me the other day but on another page I am getting an error parsing "input:checked". Also it appears that no version of IE (including 8) supports the checked CSS selector. So here's my cross browser multi-line solution:

checked = false;
try{
radios = $$('input');
radios.each(function(s,i){
if (s.checked){
checked = true;
}
});
}catch(e){}

  |  [ 0 trackbacks ]   |  related link
PHP copy/rename from FTP folder corrupts files when upload is in progress 
This took weeks to troubleshoot so maybe I can save you some time by relating the experience...

I have an application that reads files from a FTP drop folder and moves them to a queue folder. If the move is successful, a queue record is put into the database.

Now, you would have thought that is_file() would have been enough to detect if a file was ready (ie: not still being uploaded by a user). As it happens, the FTP server is 'clever' enough to give you read access during the upload, allowing you to see its progress. And so my queue script was copying and unlinking files that were incomplete.

So, I tried is_readable() - same thing.
Then I added is_writeable() - you'd think this would do it. Surely files were locked during an upload? Nope, same problem.
Then I tried doing a filesize() followed by a sleep then another filesize() and compared them. Didn't work. Then I added a filesize() > 0 check. No joy. I also made sure the stat data wasn't being cached by calling clearstatcache() each time. No difference.

Finally, the only thing that seemed to work (and yes I am still uncertain the problem has completely gone away!) is comparing a stat() on the file with a sleep() in between.

Anyway, here's the final moveFile function that appears to be working for now...

protected function moveFile($from, $to){
clearstatcache();
$this->write2log("Called moveFile ".$from. " > ".$to);
$this->write2log("File ".basename($from). " is " . intval(filesize($from)/(1024*1024/100))/100 ."MB");

if (is_file($from)){
if (is_readable($from)){
if (is_writable($from)){
//check for filesize change
$size = filesize($from);
$stat = stat($from);
sleep(5);
clearstatcache();
if ($size == filesize($from) && $size > 0 && $stat == stat($from)){
if (copy($from, $to)){
if (unlink($from)){
$this->write2log("Successfully moved ".$from. " > ".$to);
return true;
}
$this->write2log("FAILED to unlink ".$from);
}
$this->write2log("FAILED to copy ".$from. " > ".$to);
}
$this->write2log("UPLOAD IN PROGRESS ".$from);
}
$this->write2log("NOT WRITABLE ".$from);
}
$this->write2log("NOT READABLE ".$from);
}
$this->write2log("NOT A FILE ".$from);
return false;
}

  |  [ 0 trackbacks ]   |  related link
MySQL Workbench 
Nice little app for building MySQL databases under windows...
  |  [ 0 trackbacks ]   |  related link
Symfony build model errors (revised) 
If you reverse engineer your Symfony schema.yml from a database and you use the symfony plugins like sfGuard, chances are you've come across this error:

Duplicate table found: propel

The reason why this occurs is that your schema.yml will include the other plugin tables - which are now duplicated from the plugin schema.yml

The quick solution is to open your project database.yml and remove the plugin table definitions after running propel-build-schema and before running propel-build-model

If you make a lot of database changes you might want to either empty/remove the plugin schema.yml file (it's only needed for the initial installation anyway) or write a wrapper class for propel... :)
  |  [ 0 trackbacks ]   |  related link

Next