Posts Tagged ‘symfony’

quickie: creating symfony delete button

Friday, January 15th, 2010

Many months ago I had asked for help on the symfony forums on how to create a delete button using either the link_to() or button_to() method. I had tried but was always getting validation errors. Today a person asked whether anyone had figured out a solution. It prompted me to do more research into symfony’s core code and found a solution (though the solution wasn’t in the core code).

Original delete text link code:

echo link_to(
	'Delete',
	'state/delete?id='.$form->getObject()->getId(),
	array('method' => 'delete', 'confirm' => 'Are you sure?')
);

New delete BUTTON link code:

echo link_to(
	'<button>Delete</button>',
	'state/delete?id='.$form->getObject()->getId(),
	array('method' => 'delete', 'confirm' => 'Are you sure?')
);

Till Next Time

quickie: setting symfony datetime default

Wednesday, January 6th, 2010

Setting the default value for a symfony form field is one of those tasks so simple that it’s impossible to find out how to do it without a good bit of trial and error.  So without further ado, here is how to set a DateTime field’s default value:

$this->widgetSchema['start_time']->setDefault(date("m/d/Y", now()));

Till Next Time

updating symfony form values after submitting

Friday, January 1st, 2010

One thing that’s made programming on symfony very aggravating has been dealing with the forms.  Some sections of the forms are not well documented.  The main issue that I have with this at work is that we deal with GPS coordinates and the users enter their coordinates in degree-minute-seconds format but the database saves them in degree-decimal format.

I had googled for a solution to this problem before, but had not found anything to guide me to the answer.  The couple answers I had found were not very clear on getting it to work.  Till I found this.  Following these guidelines I got it to work on a test deployment of symfony.  Code below:

class Blog extends BaseBlog {
 
	/**
	 * Initializes internal state of Blog object.
	 * @see        parent::__construct()
	 */
	public function __construct()
	{
		// Make sure that parent constructor is always invoked, since that
		// is where any default values for this object are set.
		parent::__construct();
	}
	/*
	 * this function overrides the BaseBlog::save function to allow
	 * changes to be made to the object before saving to the database
	 */
	public function save(PropelPDO $con = null)
	{
		$this->setCommentCount('11');
		return parent::save($con);
	}
 
}

Till Next Time

Adding javascript to symfony form field

Tuesday, November 17th, 2009

In the users table at my company’s website there are fields for company, division, region, and location. Since each level of the company organization affects all the lower categories I have to filter out the invalid choices when a higher level choice is selected.

I’ve implemented this on some forms that I’ve created manually on the site but not in any forms that I haven’t heavily modified from the stock symfony creation.  I started googling around to find a solution but could not find a simple explanation of how to do it.  I expected to find at least some information in one of symfony’s otherwise excellent tutorials, but alas, no.

I had a minor epiphany and went digging through the forms API that symfony provides and realized that I should easily be able to do this through the sfWidgetFormPropelChoice method.  The second parameter passed is the html attributes for the form field.  I thought I had seen a form post here that said that I could add javascript code to the html attributes and not have it get converted into html entities.

I tried throwing a simple alert() inside the onchange attribute for my company box and wham! it worked!  So simple.  Code below:

new sfWidgetFormPropelChoice(
	array(
		'model' => 'Company',
		'add_empty' => true
	),
	array(
		'onchange' => "filterBy('company', 'division', this.value, 'sf_guard_user_user_division_id');" .
			"filterBy('company', 'region', this.value, 'sf_guard_user_user_region_id');" .
			"filterBy('company', 'location', this.value, 'sf_guard_user_user_location_id');"
	)
)

Till Next Time

ahhh, cronjobs!

Tuesday, May 26th, 2009

One of the features of the new platform that I am working on is the ability to automatically retrieve all new seismic activities before the end-user posts that there has been an activity.  This will make the data transfer appear instantaneous to our clients and make us look all-around awesome.

So I have a script designed to run whenever I need it to automatically get any new activities and save them to the local database waiting for the end-user.  I set it up to run every 15 minutes until I got the multitudes of old data into the new platform.  I’m talking ~170,000 activities, and each activity takes about 45-90 seconds to process.

So below is my simple cronjob command to have it run every 15 minutes 24/7/365.

*/15 * * * * php /var/lib/symfony/cron/runcron.php >> /var/lib/symfony/cron/test_cron_log.log

Till Next Time

modifying symfony database fields

Friday, May 22nd, 2009

I am making progress on my company’s new website.  I’m about 3 months in and will be launching the first version of the site in a few weeks.  So it was dismaying, to say the least, when I found that when I created the database schema for the symfony project I used the wrong data type for a few fields.

In the current platform these particular fields are stored in MySQL ‘text’ fields.  Simple, expands as needed, no problem.  I accidentally set these fields in the new schema as varchars.  My issue is that for most users, my varchar(32) field would be fine, but for that occasional user who uses lots of explosives & different delays, this would mean a loss of data.  Not something I am very keen on.

I googled a bit and could not find any information on doing a reconfiguration of the database fields in symfony and I figured it wouldn’t be too difficult to manually convert the field to a blob and modify all the accessing functions.  In the end, I was right!  Assuming you don’t make any mistakes it is remarkably simple to change a database field from a varchar to a blob.  You only need to modify two files and four functions.  So, without further adieu, I give to you the code to make a blob field accessible instead of a varchar field for symfony through propel.

(Original code is commented out for reference)

// lib/model/om/BaseActivityInfo.php
	public function getActivityExplosiveType()
	{
//		return $this->activity_explosive_type;
		$content = "";
		if(is_resource($this->activity_explosive_type))
		{
			while(!feof($this->activity_explosive_type))
			{
				$content .= fread($this->activity_explosive_type, 4096);
			}
			rewind($this->activity_explosive_type);
			return $content;
		}
		else
			return $this->activity_explosive_type;
	}
 
	public function setActivityExplosiveType($v)
	{
// this is the new code (copied & modified from setActivityExtra1) to set BLOB type
 
		// Because BLOB columns are streams in PDO we have to assume that they are
		// always modified when a new value is passed in.  For example, the contents
		// of the stream itself may have changed externally.
		if (!is_resource($v)) {
			$this->activity_explosive_type = fopen('php://memory', 'r+');
			fwrite($this->activity_explosive_type, $v);
			rewind($this->activity_explosive_type);
		} else { // it's already a stream
			$this->activity_explosive_type = $v;
		}
		$this->modifiedColumns[] = ActivityInfoPeer::ACTIVITY_EXPLOSIVE_TYPE;
 
		return $this;
/*
//	this is the original code for when the field was a simple varchar
		if ($v !== null) {
			$v = (string) $v;
		}
*/
	}
 
	public function hydrate($row, $startcol = 0, $rehydrate = false)
	{
		try {
//   ... other field's code ...
 
//		this is the original hydration code for the varchar type activity_explosive_type
//			$this->activity_explosive_type = ($row[$startcol + 36] !== null) ? (string) $row[$startcol + 36] : null;
//		this is the new hydration code for the blob type activity_explosive_type
			if ($row[$startcol + 36] !== null) {
				$this->activity_explosive_type = fopen('php://memory', 'r+');
				fwrite($this->activity_explosive_type, $row[$startcol + 36]);
				rewind($this->activity_explosive_type);
			} else {
				$this->activity_explosive_type = null;
			}
//  ... other field's code ...
			$this->resetModified();
 
			$this->setNew(false);
 
			if ($rehydrate) {
				$this->ensureConsistency();
			}
 
			// FIXME - using NUM_COLUMNS may be clearer.
			return $startcol + 92; // 92 = ActivityInfoPeer::NUM_COLUMNS - ActivityInfoPeer::NUM_LAZY_LOAD_COLUMNS).
 
		} catch (Exception $e) {
			throw new PropelException("Error populating ActivityInfo object", $e);
		}
	}
 
		if ($this->activity_explosive_type !== $v) {
			$this->activity_explosive_type = $v;
			$this->modifiedColumns[] = ActivityInfoPeer::ACTIVITY_EXPLOSIVE_TYPE;
		}
 
		return $this;
 
	} // setActivityExplosiveType()
 
// lib/model/map/ActivityInfoMapBuilder.php
 
	public function doBuild()
	{
		$this->dbMap = Propel::getDatabaseMap(ActivityInfoPeer::DATABASE_NAME);
 
		$tMap = $this->dbMap->addTable(ActivityInfoPeer::TABLE_NAME);
		$tMap->setPhpName('ActivityInfo');
		$tMap->setClassname('ActivityInfo');
 
		$tMap->setUseIdGenerator(true);
 
		$tMap->addPrimaryKey('ID', 'Id', 'INTEGER', true, null);
// ... other field's code ...
//	this is the original code for the varchar type activity_explosive_type field
//		$tMap->addColumn('ACTIVITY_EXPLOSIVE_TYPE', 'ActivityExplosiveType', 'VARCHAR', false, 32);
// 	this is the new code for the blob type activity_explosive_type field
		$tMap->addColumn('ACTIVITY_EXPLOSIVE_TYPE', 'ActivityExplosiveType', 'BLOB', false, null);
// ... other field's code ...
	} // doBuild()
 
} // ActivityInfoMapBuilder

UPDATE:
I was doing some work with these form elements and realized that the Validators need to be modified as well. It’s rather simple, all you need to do is change the validator to remove any size limitations and convert the Validator to a sfValidatorString from whatever type of sfValidator it was. Code below:

// lib/form/base/BaseActivityInfoForm.class.php
...other code...
// original code
//      'activity_explosive_type'          => new sfValidatorString(array('max_length' => 32, 'required' => false)),
      'activity_explosive_type'          => new sfValidatorString(array('required' => false)),
// original code
//      'activity_explosive_make'          => new sfValidatorString(array('max_length' => 32, 'required' => false)),
      'activity_explosive_make'          => new sfValidatorString(array('required' => false)),
// original code
//      'activity_explosive_quantity'      => new sfValidatorNumber(array('required' => false)),
      'activity_explosive_quantity'      => new sfValidatorString(array('required' => false)),
...other code...

Till Next Time

Criteria::CUSTOM – the bane of my existence, until now…

Wednesday, April 22nd, 2009

A couple weeks ago I came across a query that I needed to write that would only retrieve the records that had the same date  as another table’s record.  Since I am using propel, I looked for a simple way to format the datetime field to just match the dates in the query so that only the appropriate records would be returned.  I googled for a long time, not reaching any solution.

I ended up with a stopgap measure to get me by until I could focus more time on the problem.  I iterated through the results and used php to compare the dates and drop the nonequal date records.  Today the problem came to a head where I could not move forward with my work until I solved the issue.  Since I’m using mysql and propel, I ended up creating a custom criteria using the mysql ‘DATE’ function.  I know this is suboptimal in that my query is now tied to mysql, but I really don’t expect to be changing databases soon, or ever.

Most of the solutions that I found online would not work with the DATE function for one reason or another (another = I couldn’t figure it out).  I finally found my solution in the symfony forums (can you believe it!?!?!) here.  For some reason google failed me on this one.  So out of the billions of pages online I had to find the one (1) that had my solution.  Luckily time_to_find_solution < losing_my_mind.  So the very simple solution is this:

$c->add(ActivityInfoPeer::ACTIVITY_EVENT_TIME, 'DATE('.ActivityInfoPeer::ACTIVITY_EVENT_TIME.')= DATE('.ActivitySeismoInfoPeer::ASI_EVENT_TIME.')', Criteria::CUSTOM);

Till Next Time

adding OR conditional to a symfony query

Thursday, April 9th, 2009

I had to do some looking to find how to do an ‘or’ statement in symfony with propel.  I found out at a google’s group here and the api documentation from propel is here.  Once I found the information it was surprisingly easy.  Below is the code I ended up using to select records either updated in the last two weeks OR activities that are delayed AND activities that the posting times are NULL (implying they are not posted yet).

$c = new Criteria();
$c->AddDescendingOrderByColumn(ActivityInfoPeer::ACTIVITY_EVENT_TIME);
 
$criterion = $c->getNewCriterion(
ActivityInfoPeer::UPDATED_AT, date("Y-m-d H:i:s", time() - 1209600), Criteria::GREATER_THAN)->addOr(
     $c->getNewCriterion(ActivityInfoPeer::ACTIVITY_DELAYED, 1, Criteria::EQUAL)
     )->addAnd($c->getNewCriterion(ActivityInfoPeer::ACTIVITY_POST_TIME, null, Criteria::ISNULL)
     );
$c->add($criterion);
 
$this->pending_activities = ActivityInfoPeer::doSelect($c);

Till Next Time

creating symlink in linux

Sunday, March 22nd, 2009

Here’s another quickie post.  I have to create symbolic links occasionally, and enough time has passed in between the uses that I always forget the syntax to create the link.  I got this bit of code from here.  So, without further ado:

ln -s <Destination> <linkName>

So for instance, I need a link from /var/www/web to /var/lib/symfony/web, the following works:

ln -s /var/lib/symfony/web /var/www/web

And voila! Done

Till Next Time

quickie bash cmd to copy all files except a single given file

Friday, March 13th, 2009

In working on my new prod server I only have write access to the symfony folder and www folder.  This isn’t a big deal in actual development, just in backing up my files.  I have become a zealot when it comes to backing up.  Not just backing up files, but keeping a log of where the development stands for each backup.

For instance, before I launch the backend application in symfony, I do a backup and then I do another backup right after I launch it, before I make any modifications.  This seems to help me when I mess something up so bad that I cannot recover from my mistakes.

Since I only have access to the two folders that I am going to be backing up, I don’t want to backup the already backed up files, I would start to take up an exponential amount of space for each backup.  Did a quick google and found the solution here.

cp -r `ls --ignore=file1` destinationDir

Simple and it works. :-)

Till Next Time