After implementing query caching using Doctrine’s Doctrine_Cache_Apc interface in a Symfony application I am working on, when running the application’s functional tests, warnings were returned intermittently in a few places
$ [apc-warning] Potential cache slam averted for key ...
In APC >= 3.0, an apc.slam_defense configuration option was added in attempt to avoid repeated writes to the same APC cache key as might occur under very high traffic. This apc.slam_defense option was later removed due to having been deprecated in favor of apc.write_lock as of APC >= 3.0.11. This is enabled by default, so the first thing I tried in my development environment was disabling this option. A simple test case will still fail though with apc.write_lock disabled.
apc_store('my_key', 1);
apc_store('my_key', 2);
echo apc_fetch('my_key'); // outputs 1, not 2
One of the more recent comments in this PECL ticket for APC offers a patch that can be applied to the latest release of APC before compiling it. This patch re-introduces the previously removed apc.slam_defense option. For my development environment only (since the cache slam warnings thrown in this environment due to my functional tests are irrelevant), I fixed the cache slam warnings by following these steps
php.ini, add the newly recognized apc.slam_defense=0 With apc.slam_defense in place and disabled, the test case above and my application’s functional tests run without any cache slam warnings.
There may be times when part or all of a text/plaintext version of an action’s template needs to be rendered for use from within another action who’s display format is set as text/html. For example, if there is a text/plaintext version of an order receipt that appears within an application, and that same version of the order receipt needs to be mailed to a user from within a separate action, we need to tell the order receipt to render in text/plaintext otherwise it will attempt to render in the format of the current action; in this case text/html. This is assuming the email is being sent as text/plaintext itself and the rendering action’s format is text/html.
Symfony offers a sfWebRequest::getPresentationFor() method which provides the functionality to render an action’s view from within another action, even if the calling action resides in a separate module. The trick is specifying the format for the other action while maintaining the requested format for the current action. The getPresentationFor() method signature is limiting in it’s support for specifying a format, so the only option appears to be as follows.
// In the current action
$format = sfContext::getInstance()->getRequest()->getRequestFormat();
sfContext::getInstance()->getRequest()->setRequestFormat('txt');
$otherActionContent = sfContext::getInstance()->getController()->getPresentationFor('moduleName', 'otherActionName');
sfContext::getInstance()->getRequest()->setRequestFormat($format);
unset($format);
The above code
Doctrine provides a stock Sluggable template behavior that can be applied to models, generating a slug based on one or more columns for a Doctrine_Record instance.
In most cases it is best practice not to modify a slug after it is generated, since one or more external sources may be referencing a URL to the Doctrine_Record instance by the original slug. If the slug is modified, those URLs referencing the original slug will become broken. For this reason, Doctrine’s default behavior is to have the canUpdate option for the Sluggable template be set to false.
There may however be reason to override this disabled canUpdate behavior under certain conditions. Doctrine 1.2 does not seem to provide an easy way to access a specific Doctrine_Record_Listener and modify an option associated with that listener for a given Doctrine_Record instance. Assuming there is only a single instance of any given listener associated with a Doctrine_Record, it’s fairly straightforward to find the desired listener within the Doctrine_Record_Listener_Chain. Applying this search conditionally to a Doctrine_Record::preUpdate() hook would look something like is shown below.
// In your Doctrine_Record class
public function preUpdate($event){
if (true) { // Conditions to check against for whether or not to allow the slug to be modified go here
try {
SomeUtilityClass::getListener($event->getInvoker()->getListener(), 'Sluggable')->setOption('canUpdate', true);
} catch (Exception $e) {
// Silently fail
}
}
}
// In SomeUtilityClass
class SomeUtilityClass {
static public function getListener(Doctrine_Record_Listener_Chain $chain, $search) {
$i = 0;
do {
if ($chain[$i] == null) {
throw new InvalidArgumentException('The requested Doctrine_Record_Listener is not associated with this Doctrine_Record instance');
}
if (get_class($chain[$i]) === sprintf('Doctrine_Template_Listener_%s', $search)) {
return $chain[$i];
}
} while (++$i);
}
}
The above getListener() method is required since it appears the only access to Doctrine_Record_Listener is via an implementation of PHP’s predefined ArrayAccess interface. Since the Doctrine_Record_Listener_Chain class only implements the set() and get() methods from the ArrayAccess interface, the only way to access the listeners is via their automatically assigned numeric keys. There is no way to directly request a specific listener by name through the Doctrine 1.2 API, thus the necessity for the do...while loop.
Setting up a new Website Payments Pro account for integration with an application I’m working on, it required a sandbox account be setup through http://developer.paypal.com/. Though the Test Accounts page is very simple to work with, it was a little tricky sorting out exactly how to integrate a Website Payments Pro account with a business test account that will actually process payments successfully.
I finally came across this help document. I can only assume this process seems immensly over-complicated to me because I am new to this type of integration with PayPal’s sandbox. I understand the necessity for all of the configuration, but am a bit unclear why developers are required to manually enter so much dummy account information with no guidance provided throughout the process directly through the signup forms.
Update: After hours of sifting through the mess that is PayPal’s developer network/documentation/sandbox site, I have opted to use Authorize.net. Getting test credentials was simple, and with this simple and concise class I was making test payment through my application within 45 minutes.
Symfony comes with some great i18n and l10n support. The DateHelper comes with functionality for templates to provide locale-specific date formats. There are a bunch of default formats that can be easily used as
format_date(strtotime('now'), 'P', 'en_US'); // Outputs 'Monday 7 June 2010'
format_date(strtotime('now'), 'P', 'fr_FR'); // Outputs 'Lundi 7 Juin 2010'
Some of the pre-defined patterns are constructed using special token patterns. These tokens can be passed to the 2nd parameter of the format_date() function above to generate custom formatted locale-specific date/time stamps.
format_date(strtotime('now'), 'EEE, MMMM dd, yyyy hh:mm a'); // Outputs 'Mon, June 07, 2010 12:40AM'
It doesn’t appear detailed information is available in any of the main documentation books or in the source code regarding the tokens available for date/time formatting, but I did come across a wiki page in the symfony trac.
During a normal development cycle, multiple branches of trunk may exist simultaneously with different features/fixes being developed within each. In order to keep trunk relatively stable at all times, it is a good idea to merge any changes to trunk since the branch was created into that branch when the branch is ready to be pushed into trunk. Confusing? The process is as follows
branch
branch (other developers are doing the same in their respective branches)
branch
trunk since the branch was created into the branch
trunk changesbranch back into trunk
This is by no means the only way to manage development of a new feature/fix within Subversion, and I make no claim that it is the best. This is simply what works for my team at work presently. The end of the process described above (starting with 3) looks as follows
$ cd /path/to/branch
$ svn log --stop-on-copy # Run this from within the branch root - notice the revision # when the log output stops
$ svn merge -r ###:HEAD /path/to/trunk . # Here ### is the revision number from above
# Resolve any conflicts and test all code again in the branch
# Now to get the changes from the branch merged successfully back into trunk
$ cd /path/to/trunk
$ svn merge /path/to/branch -r ###:HEAD --accept theirs-full
$ svn resolve -R --accept working *
$ svn ci -m "Merging branch ____ into trunk" # Commit the branch merge into trunk
The 2nd and 3rd from last lines above are the ones of interest; they are the ones responsible for getting the work back into trunk. These lines are really only necessary since we had first merged work from trunk into the branch. The first line
$ svn merge /path/to/branch -r ###:HEAD --accept theirs-full
merges all changes from the branch since it was created back into trunk. This includes all code merged from trunk to the branch, so we are guaranteed that the branch has the latest and greatest of all code. As such, we force SVN to resolve all conflicts by accepting the branch copy’s version of every file within our working trunk copy. The next line
$ svn resolve -R --accept working *
Resolves any tree conflicts that have been introduced.
After learning Github is now offering SVN support (nearly all of my development work is done using SVN), I decided it was time to properly version my small changes to the great gRaphael library by forking the original code with my own account. I also decided to start to maintain smaller utilities I write for personal use through git on Github as well. The first of these packages is \Deefour\SpellCheck.
Introducing ”SpellCheck v1.0”. As mentioned in the README,
SpellCheck leverages “…the XML request/response used by the Google Toolbar…” accepting “… a string to be transformed into a corrected version of itself.”
This class simply makes all corrections suggested by Google to the original string passed in. Admittedly, this is not as flexible as some will like, but for now it suits my needs and is a great start. Some small points:
Usage instructions and code can be found in the v1.0 Tag on GitHub.
When browsing to an anchor within an page, all browsers (that I know of) scroll the page to the anchored element such that the element is at the very top of the visible browser window. This is a problem when a site design includes a fixed element at the top of the browser window. A little bit of Javascript (via MooTools) can fix this:
var AnchorFix = new Class({
Implements: Options,
options: {
fixed_element: null
},
initialize: function(options){
this.setOptions(options);
this.applyTrigger();
},
/**
* Applies the onhashchange event to the window
* to listen for a new anchor being browsed to by the user
*/
applyTrigger: function(){
var fn = window.onhashchange || $empty;
window.onhashchange = function() {
fn();
this.reScrollWindow();
}.bind(this);
},
/**
* Calculates the proper scroll point for the window based
* on the height of the fixed element at the top of the page,
* allowing the anchored element to be visible under the fixed
* element
*/
reScrollWindow: function(){
var hash = window.location.hash.trim().substring(1);
var element = ($(hash) != null) ? $(hash) : $(document.body).getElement('*[name="' + hash + '"]');
if (element != null) {
var position_y = element.getPosition().y;
var bar_height = $(this.options.fixed_element).getSize().y
window.scrollTo(0, (position_y - bar_height - 5));
}
}
});
// Instantiate a new instance of the class to get started
var fixMyAnchors = new AnchorFix({$('idOfTheFixedElement')});
Not all browsers support the Javascript onhashchange event (read: IE7 and earlier). A bit of the applyTrigger() code above was modified from MooHistory, and with a bit of tweaking if desired, support could be added to the code above for earlier versions of IE (check out their source to see how they handle IE6/7).
arguments is a local object variable available within any function in JavaScript. Arguments can be accessed as shown in foo() below.
function foo(){
console.debug(arguments); // ['a', 'b']
console.debug(arguments[0]); // 'a'
}
foo('a', 'b');
This is convenient for functions that may need to accept an arbitrary number of parameters. But if these arguments need to again be passed on to a 2nd function from within the first, a problem arises:
function foo(){
// ...
bar(arguments);
}
function bar(){
console.debug(arguments[0]); // ['a', 'b']
console.debug(arguments[1]); // undefined
// ...
}
foo('a', 'b');
Notice that arguments[0] in bar() above now contains an array of the arguments passed to foo(), while arguments[1] is undefined. MooTools has an
.attempt function prototype (See the documentation) that fixes this issue.
function foo(){
// ...
bar.attempt(arguments); # Call bar() using MooTools attempt()
}
function bar(){
console.debug(arguments[0]); // 'a'
console.debug(arguments[1]); // 'b'
// ...
}
foo('a', 'b');
Looking at MooTools 1.3b1.1 Source, the arguments are passed to the requested function using apply() (See the documentation).
In MooTools the $() is used in part to ensure the element passed to $() is extended by MooTools. Clientcide points out a great tip with the native Class toElement() function.
Aside from the benefits from the use of this from outside of a class passing an instance variable to $(), I like to use toElement() in combination with $(this) from within my Class objects simply for brevity.
var someClass = new Class({
Implement: [Options],
options: {
domReference: null
},
initialize: function(options){
this.setOptions(options);
// Here, $(this) will reference this.options.domReference :)
$(this).setStyle('background-color', '#F00');
}
toElement: function(){
return this.options.domReference;
}
});
var someInstance = new someClass({
domReference: $('some-dom-element-id')
});
Obviously the example is a little bit ridiculous just to style an element’s background red, but the point is for me it’s much cleaner having the option to write
$(this).setStyle('background-color', '#F00');
than
this.options.domReference.setStyle('background-color', '#F00');
The majority of the file management I do at work is through the terminal, however sometimes it is necessary to view/work with files through Nautilus. I’ve added the following command to my ~/.bashrc, causing openme to launch the current working directory in Nautilus.
alias openme='nautilus --browser . 2> /dev/null'
To prevent user-generated content formatted with Markdown from being re-parsed by the Markdown parser every time it is called to be rendered as HTML, it is best practice to store the parsed/converted HTML version of the original Markdown text alongside the original Markdown markup. The parsing of this user-generated content can only be done as necessary using Doctrine’s preSave event listener.
First, the schema for the table can be very simple.
Message:
columns:
message:
type: text
notnull: true
raw_message:
type: text
notnull: true
The raw_message field will contain the Markdown text as entered by the user. The message field will contain the converted HTML equivalent of the user-generated Markdown syntax.
When saving the record with Doctrine, only the raw_message field needs to be set manually.
$message = new Message();
$message->setRawMessage($some_posted_form_message);
$message->save();
Finally, in the Message class (an implementation of Doctrine_Record), a preSave() event listener is added to conditionally parse the user-generated Markdown into HTML and store it to the message field.
class Message extends BaseMessage {
public function preSave($event){
if (!$this->exists() || array_key_exists('raw_message', $this->getModified())) {
$markdown = new MarkdownExtra_Parser();
// strip all HTML tags
$value = htmlentities($this->raw_message, ENT_QUOTES, 'UTF-8');
$this->message = $markdown->transform($value);
}
}
// ...
}
Now, whenever a Message is saved, if the raw_message field value has been changed, it will be re-parsed, converted to HTML and stored into the message field.
Hoping there is a simpler way that I am missing, here is how to begin a new transaction with Doctrine 1.2 through Symfony 1.4. It was the call to sfDoctrineDatabase::getDoctrineConnection() which I had to lookup in the docs1.
$connection = sfContext::getInstance()->getDatabaseManager()->getDatabase('default')->getDoctrineConnection();
$connection->beginTransaction();
try {
// Do work for the transaction ...
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
// Handle exception ...
}
Recently I needed to parse all unique email addresses from a very large plaintext log file. A simple grep would not suffice because there were many cases where multiple email addresses appeared on the same line.
Realizing there are many solutions to this problem, here is the one I came across1 which I found most suitable for my needs.
perl -wne'while(/[\w\.\-]+@[\w\.\-]+\w+/g){print "$&\n"}' path/to/log_file | sort -u > parsed_unique_sorted_emails.txt
Some Conversation model might have a many-to-many relationship between itself and some Participant model through some ConversationsParticipants model. By default in Doctrine, to get all Participants for some Conversation, the magic finder for
$participants = Conversation->Participants;
would return Participant instances in the order they were created (ordered by the primary key). When a custom ordering of the list of Participants is required, the magic finder must be overloaded within the base model. For example, if the participants are to be ordered by username ASC, we would create a getParticipants() method in the Conversation model like this
public function getParticipants(){
$q = DoctrineQuery::create()
->from('User u')
->innerJoin('u.ConversationsParticipants cu')
->where('cu.conversation_id = ?', $this->id)
->orderBy('u.username ASC');
return $q->execute();
}
This is great for models which have been persisted in the database already, but becomes problematic when retrieving the Participants relation for some new Conversation which has yet to be saved into the database. Since the above overloaded getParticipants() finder is querying the database against a Conversation which does not yet exist in the database, we need to conditionally ignore this custom finder’s query and default back to the magic finder within the Doctrine_Record class.
public function getParticipants(){
if ($this->isNew()) {
$q = DoctrineQuery::create()
->from('User u')
->innerJoin('u.ConversationsParticipants cu')
->where('cu.conversation_id = ?', $this->id)
->orderBy('u.username ASC');
return $q->execute();
} else {
return parent::__get('Participants');
}
}