Jobs for Symfony developers
Saturday, March 13th, 2010Worth knowing about: a listing of jobs for Symfony developers.
Worth knowing about: a listing of jobs for Symfony developers.
Here is a great post on extending a blog plugin for Symfony. There is a new hack attack going around for WordPress, so I’m thinking about switching to Symfony for my blogging.
A controversial claim, but he makes an interesting case. Russ argues that Symfony sets a high standard for all other open source projects to aspire to. No doubt this is true.
Over on Symfony Nerds, I wrote about Potencier’s ideas about a template engine. I just noticed that Eli White had also written an intelligent reply, well worth reading.
I’ve a new post up at Symfony Nerds. In it, I look at the implications of a RESTful architecture for Symfony. Should every module just have 4 actions, read, write, update and delete?
Scott Meves points me to this presentation by Kris Wallsmith. Lots of information about how to scale up Symfony, and a plugin is thrown in for handling multiple database connections. I intend to come back and dive into that subject more later on.
I agree with this: Netbeans is a good IDE for Symfony development. I think this is especially true if you, like me, also develop with JVM languages. This last year I was doing some Java/Swing and Groovy projects, so I started using NetBeans again. It has a plugin for doing Symfony work – very handy.
Colin Steele writes about the challenges that he and his team are facing at Hotelicopter:
We’ve officially run headlong into one of Ruby on Rails’ deficiencies: programming in the large. We’re not interested in computer science-y solutions, only pragmatic ones.
I’m curious what is excluded by the phrase “computer science-y solutions”? I would normally interpret that to mean “we are looking for well tested solutions with wide deployment” but elsewhere he writes:
We’re currently investigating a spectrum of new technologies in the NoSQL realm, including Tokyo Tyrant, MongoDB, Amazon’s SDB, CouchDB, Voldemort, and more. Tis’ a dizzying mix, and things are popping in the space.
So clearly they are looking at some cutting edge technologies. Colin links to an essay about Programming in the large which includes this:
Maintenance and locality are strong arguments in favor of immutability. The less aspects of an object can be changed, the less you have to worry about the execution history. If an object has a two-phase initialization sequence (e.g. this is so in C++ if you need a virtual function during initialization), you have to make sure that the objects are properly initialized; code that gets handed over such an object will have to check that it’s initialized (if only in an assert()). This all vanishes if the language makes sure that no object remains uninitialized, and doesn’t force a two-phase initialization on programmers like C++. (In C++, the “wrong” design decision was that objects mutate from the base type to the subtype when the various constructors are run. It’s this kind of far-reaching consequences (IOW non-locality) that makes language design an art.) If you take immutability to its extremes, nothing can ever be changed. If you wish to change the world, you write a function that returns a list of changes and let the run-time system inspect that list and execute the proper actions. If you have an interactive program, you emit a list that has a function pointer at its end; the function gets fed the next input and is expected to generation another action list.
In the last few years, many programmers have pointed to mutability as one of main problems they face when they build larger systems. Chas Emerick does a good job of highlighting the problem in his post “All my methods take 316 arguments, and I like it that way”
316 arguments to a method (which I don’t think is actually possible in the jvm, but bear with me)? “That’s absurd!”, you’d say. The problem, of course, is that the 3-arg doSomething actually has far more arguments than its signature implies:
The behaviour of every function in a mutable, imperative environment is dependent upon the state of all of the other (variables|attributes|bindings|whatever) in your program at the time the function is invoked.
So, if you have 313 other variables in your program, that 3-arg doSomething is functionally (ha!) operating over 316 arguments.
Would you ever intentionally write a method signature that takes 316 arguments? Would you use any library that contained such a function signature? No? Then why are you using tools that force such craziness upon you?
Chas says “The languages are ready” and he links to some of the major functional languages: Erlang, Clojure, F#, and Fantom. In comments, his readers add in their favorite functional languages: OCaml, Haskell, etc.
One of his readers challenges the idea that functional languages are safer than imperative languages by offering this:
Regarding functions changing state, what about things like this in clojure, Isn’t it like global variables in imperative lang?
(def state (ref #{}))
(defn function that updates state)
(defn another function that updates state)
Chas responds:
You bet. Clojure is not a purely functional programming language, so you can have as much shared state as you want – but the language is going to make you work for those bits of shared state, so you have to “pay” for them. Conversely, imperative languages like Java et al. make you work to achieve immutability, and provide nothing in the way of enabling persistent data structures, etc.
The point is that defaults matter, a lot.
I like the word “default” in this context. In his 2001 book, Effective Java, Joshua Bloch wrote “Favor immutable objects over mutable.” When writing a big system in Java, you work to make your system immutable. In a language like Clojure, the default is just the opposite – you work to make parts of your system mutable.
I have very little experience with functional programming. I am just learning Clojure now (Lisp redone for the JVM). I can not say what benefits its brings. I’m looking forward to learning more in this area. It’ll be interesting to see where functional programming comes to be regarded as a “best practice”. Certainly, it will be interesting to see if CTO’s start using these languages at startups, or whether they will be regarded as “computer science-y solutions”.
I’ve somewhat more experience with the web app frameworks that have emerged since 2004. I’m interested in what Colin wrote here:
I suspect as we muddle along we’ll develop a component-level (service level if you prefer) version of the Law of Demeter, which will drive us to make the right decisions for decoupling. I’m not too worried about that. However, we definitely have issues with reuse. Currently the Ruby on Rails state of the art solution for reuse is the gem. Which, let’s face it, is a pathetic solution.
Some of the frameworks seem to encourage bad habits. I’ve already written of Symfony’s weaknesses in Symfony versus The Law Of Demeter: does Symfony promote bad habits?.
When Ruby on Rails first emerged it was targeting web apps, not web services. Rails has a lot of imitators: Groovy/Grails, PHP/Symfony, etc. These all help create web sites, but not necessarily web services. I suspect a new generation of frameworks will be needed to make this kind of work easier:
The place we’re aiming for is a highly decoupled (and scalable), cohesive set of services, joined through REST APIs and/or fully reused common business models.
In their book Restful Web Services the authors Leonard Richardson and Sam Ruby talk about “the human web” and the “programmable web”. This is from page 2:
The Web you use is full of data: book information, opinions, prices, arrival times, messages, photographs, and miscellaneous junk. It’s full of services: search engines, online stores, weblogs, wikis, calculators, and games. Rather than installing all this data and all these programs on your own computer, you install one program – a web browser – and access the data and services through it.
The programmable web is just the same. The main difference is that instead of arranging its data in attractive HTML pages with banner ads and cute pastel logos, the programmable web usually serves stark, brutal XML documents. The programmable web is not necessarily for human consumption. Its data is intended as input to a software program that does something amazing.
Originally, frameworks like Rails were created to help speed the production of sites for the human web. They have evolved since then, Rails in particular. In fact, Richardson and Ruby use Rails for many of the examples they offer in the book, about how to correctly build a RESTful web service. And yet, the scaffolding systems in these frameworks still tend to automate the production of CRUD web pages, rather than PGPD services. (I do not know the state-of-the-art with Rails, so someone can tell me if I’m wrong about its scaffolding.)
Richardson and Ruby suggest that every module (resource) in a RESTful web service should expose just 4 actions:
POST
GET
PUT
DELETE
These are the HTTP verbs, and they roughly correspond to the standard CRUD actions, except that POST is used for both Create and Update, and PUT is used for uploading files:
Create/Update
Read
Upload
Delete
I suspect we need a new generation of frameworks, or at least new scaffolding systems for the existing frameworks, that automate the setup of PGPD services. That seems like the next obvious step forward.
[What follows is a comment I posted over at Hacker News.]
My impression is that there was a stretch when some combination of the public mood and the government’s emphasis conspired to encourage small startups. The 1980s and 1990s were clearly good in this respect. The mood of the last decade has been increasingly punitive. Sarbanes-Oxley is the most clear example of this. What once would have been treated as a civil matter is now treated as a criminal matter. Entrepreneurs are now faced with jail time instead of lawsuits. This can only have a chilling effect on innovation. I think it is urgent that everyone who cares about entrepreneurial culture in America to make the argument that innovation in business depends in part on tolerance, and that, in practical terms, this means most matters of conflict should be treated as civil rather than criminal cases.
A comparison might be made to the evolution of bankruptcy law. Before the mid 1800s, most Western countries treated bankruptcy as a criminal matter, rather than a civil one. The liberalization of bankruptcy law was one of the factors that allowed our modern economies to gain the dynamic nature they now enjoy. The public’s mood changed during the 1800s as it became more obvious that many times entrepreneurs failed with their first venture. They needed a second chance, when they were often more successful. John Bayer, who created what became Bayer aspirin, is an outstanding example of this – at first he tried to build a liquor business, but it failed. His father-in-law was suffering arthritis, and therefore drinking large amounts of willow bark tea – the only known source acetylsalicylic acid. John Bayer then put the willow bark tea through the distillery equipment he’d bought for his liquor business – and thus asprin was created. The point is, he needed a second chance to become successful. Many entrepreneurs are in this category.
Since this is Hacker News, I would guess that most of us know someone who has tried to do a startup, and failed on their first attempt. Many of us also know entrepreneurs who tried again, and met with greater success on successive tries. Tolerance of failure is the first pre-requisite of a dynamic economy.
More so, if you have any friends who have attempted to launch a startup, ask yourself under what circumstances you think your friends should go to jail.
I posted a similar comment some months ago, and I mentioned how many lives might be saved by the next wave of medically-focused startups. Someone responded:
“When you cross the line into experimenting with medical treatments, you’re not gambling with other people’s money, you’re gambling with lives. You can’t just equate it to any other kind of start up, it has to be held to a higher standard.”
I want to repeat, many, many industries can lead to people’s deaths. There is nothing unique about medical innovation. If you build a new kind of jet engine, which gets through testing but which then is responsible for a spectacular crash, then your product has killed a few hundred people. And yet, unless there was fraud in the documentation of the tests, there have not been criminal cases in the past. Right from its creation, decades ago, the FAA has taken a strong line against criminal – the feeling has always been that criminal prosecutions would stifle the free flow of information, and the only way to save lives over the long-term is through the free flow of information.
Many other fields can cause people to die – industrial automation, the transport and disposal of toxic chemicals, the construction of buildings (which could then fail and kill people). All industries are in need of innovation all of the time, yet innovation brings with it risk, including the risk of death. How much innovation will we get if we make these matters criminal?
I should emphasize, just in case people forget, that fraud has always been criminal. It has been criminal for centuries. So the move to criminalize more aspects of business is not a move to make fraud criminal. If you think that the Sarbanes-Oxley Act made fraud criminal, then you are mistaken. Fraud has always been criminal.
Sarbanes-Oxley is representative of the new trend. The overall goal was to encourage greater accuracy in the reporting of a company’s financial health. This goal could have been reached through a variety of methods, including both the carrot (rewards) and the stick (punishments). Rewards could have included tax breaks for meeting some additional level of compliance. Punishments could have included fines levied against companies that failed to meet a higher level of compliance. These approaches would not have raised the risk of jail time for CEO’s. Instead, Sarbanes-Oxley decided to go with the heaviest kind of punishment of all – to treat infractions as criminal offenses, potentially meriting jail time.
This punitive attitude is going to have a chilling effect on the amount of innovation we can expect in any field.
I’ve a new post up at Symfony Nerds. This looks at the evil of utility classes full of static methods, a vice that I’m guilty of on every project. I examine possible ways to refactor the code to get a healthier overall architecture.
Darren Hoyt and I have launched a new website. My ideas about this site grew out of m frustration with Experts Exchange. I’ve written about the evolution of my thoughts over on the WP Questions blog.
Darren has written a summary of everything that WP Questions is, and isn’t.
We used the Symfony framework to build this site. I’ve written a somewhat technical post, over on Symfony Nerds, explaining why this was a good choice for us.
The site took Darren and I about a month to develop. I thought about the right structure for the database during the last week of October, and we got to work in early November. We both took a month long break from doing work for clients, and pretty much just worked on this site, full time, for the month. Our focus was a minimalist but sufficient feature set, a clean design, and a database structure that will be flexible in the face of future changes (among other things, I was wary of too many foreign key relationships).
This last spring I was thinking about question and answer sites where money might be exchanged. On May 5th, I wrote this in a email:
“I’ve the easiest time imagining building out a site for a particular niche… Personally, I’d love a site devoted to programming, where I could put up a question for $20 or $30. Just this week I lost 4 hours tracking down an obscure conflict in the Javascript used on a site – one script was used to fix the PNG transparency problem in IE6, and another script, which preloaded large images used in rollovers, was triggering the first script too often, adding extra images to the page. I would have loved to pay $25, or even $50, to let some IE6 specialist tackle that one. I could imagine being a customer of such a site.”
Our first day went well:
1,389 visitors
200 users signed up
A few paid questions
We are starting off focused on a small niche: web developers who use WordPress. If the site is successful, we will roll out similar sites for other, broader technologies: Java, Ruby, Rails, Grails, SQL, .NET, Oracle, etc.
As I said today on our blog, in reaction to user responses:
I’ve been working on websites for 10 years, and I’m very pleased with how our first day went – much better than average. We received a lot of valuable bug reports and thoughtful feedback. I was pleased to see some questions posted. Our fees are 9% plus 50 cents. PayPal takes about 3% and 30 cents, so our net profit from yesterday was less than $10 dollars, but, hey, that means we made more on our first day than Twitter made during its first 2 years. Which leaves me hopeful that we are, in fact, offering a service that provides real utility to people. And as we listen to your feedback and implement the better ideas, we hope to be able to offer an even greater service in the future.
Just saw this site referenced on the user mailist. Symfony-Check.org is a useful list of things to check when building a Symfony-backed website.
I’ve a new post up at Symfony Nerds, which looks at some of the bad coding practices which are common on some of the Symfony projects that I’ve worked on.
I’ve a new post up at Symfony Nerds. Fabien Potencier, the lead developer on Symfony, has recently introduced 2 new components related to templates in Symfony, including Twig, a template engine that will be introduced in Symfony 2.0. I try to offer an overview of the whole debate around these developments.
I’ll now be contributing to the Symfony Nerds blog. My first post is up, and it mostly reviews various bits of Symfony news and articles that I found interesting during the last week or so.
For people new to Symfony, this is a good write-up of the new forms framework, introduced a year ago in Symfony 1.1.
I am curious about Mobicules weblog. Some of their posts are self-serving, but they seem to be trying to get some real information out, which is more than what I’ve seen so far from most of the sites of Indian firms that I’ve looked at. How should I read this post on which platform to use for a massive social site that can scale to tens of millions of users?
ELGG: Due to a very flat and normalized database structure, the only way to scale horizontally with ELGG is to duplicate the database using MySQL replication on multiple servers. The negative with this approach is that it ends up duplicating the complete database, with the result that each machine running a copy of the replicated database will have to be very powerful server, rendering the solution expensive. (MySQL clusters is a standard way of doing it)
Drupal: Similar problems as ELGG with Drupal, but database is not as flat and normalized as ELGG. Scaling up in a similar manner as described for ELGG wity MySQL clusters would probably be cheaper with Drupal.
Symfony: Allows us to use a custom database structure. We can design the database and replicate it as we like. Symfony also uses its own query/object caching mechanism, which is efficient. As an example, the Yahoo bookmarks site supports 20 million users on Symfony.
…Our recommendation in a case where you are looking to scale up to 10s of millions of users would be write everything from scratch (and not use a ‘platform’ like ELGG/Drupal), that allows you to customize and tweak anything and everything. Symfony seems to have a good reputation for enabling creation of very large websites, and so, we would recommend using Symfony as a framework.
I actually agree with their conclusions.
I’m working on image gallery to be used on a site built with Symfony. So I’ve been reading up on all the different techniques out there for managing images for such a site.
Sitepoint has a good tutorial on how to use the sfThumbnail plugin:
We’ll use the sfThumbnail class provided by the plugin to create a thumbnail of each uploaded file. The best place to do this is in the setFilePath() method of the Photo class. Add the following to the Photo.php file:
// in lib/model/Photo.php
public function setFilePath($value)
{
parent::setFilePath($value);
$this->generateThumbnail($value);
}
public function generateThumbnail($value)
{
parent::setFilePath($value);
$uploadDir = sfConfig::get(’sf_upload_dir’);
$thumbnail = new sfThumbnail(150, 150);
$thumbnail->loadFile($uploadDir.’/’.$this->getFilePath());
$thumbnail->save($uploadDir.’/thumbnail/’.$this->getFilePath(), ‘image/png’);
}
One question I had to look up was how to restrict which files users are allowed to upload. That thread on the forum was useful.
Working with Symfony is the first time I’ve worked with Yaml files. As such, I still have to look up the info when I’m trying to do something like get an array out of a mass of Yaml configurations settings. Searching around, for info on the subject, I found the following, helpful conversation.
ifilipov writes:
Hey guys, my navigation is located in app.yml
all:
navigation:
Home: index.php
About us: about.php
Events: events.php
Mailing List: mlist.php
Contact Us: feedback.phpi’m trying to put all this in array, but it doesn’t work.
$nav = sfConfig::get(’app_navigation’);
print_r($nav);
halfer replies:
I believe to collapse things down to an array, you can also use the dotted syntax, something like this:
all:
.settings
navigation:
Home: index.php
About us: about.php
Events: events.php
Mailing List: mlist.php
Contact Us: feedback.phpThe dotted word can be anything, and is ignored by the YAML parser. Then to access it:
$nav = sfConfig::get(’app_navigation’);
print_r($nav);
Now things get strange.
I thought it would be useful to double-check with the official Yaml spec, to see what the dot really means. But the dot is not in use in any of the examples given in the spec. Instead,
To do a 2 dimensional array, there is this:
Example 2.3. Mapping Scalars to Sequences
(ball clubs in each league)american:
– Boston Red Sox
– Detroit Tigers
– New York Yankees
national:
– New York Mets
– Chicago Cubs
– Atlanta Braves
Here is something I take to be what in PHP would be considered an associative array inside of non-associative array:
product:
– sku : BL394D
quantity : 4
description : Basketball
price : 450.00
– sku : BL4438H
quantity : 1
description : Super Hoop
price : 2392.00
But I find no examples using the dot notation. Which is odd.
(As to the conversation on the forum, partly I link to these articles to give them some rank with Google. I find that Google does a poor job of figuring out what pages are relevant to Symfony searches. I think this is partly because Symfony bloggers don’t link to many tutorials or quick tips, so Google doesn’t have many links on which to form a judgement about what is important.)
I’ve already mentioned one use of public_path(), which is to leave as much HTML as possible in the templates, so that designers have an easy time working with them.
This conversation was related, and caught my interest.
Mo Mughrabi wrote:
Generate absolute URL for upload directory
I was trying to generate an absolute URL inside my form classes using sfContext::getInstance()->getController()->genUrl(); but apparently genUrl only can be used when supplied a route or module/action but i cannot get it to return the absolute path of my uploads folder. Any idea how can i do that?
Eno responded:
We never found a good solution for this (we run across a cluster where we need absolute and cross-domain links). Now we are using the sfDomainRoutePlugin to give us this functionality in url_for() and link_to().
And then Mo Mughrabi said:
I found a way which helped me return the absolute url for any location i
need through the public_path helper.First i had to include the helper through the getConfigurations
sfContext::getInstance()->getConfiguration()->loadHelpers(array(’Url’));
and then just use the public_path(’uploads/file.jpg’);
Reading this. I thought this was a funny commit note:
added more deprecated stuff
I mean, you can kind of guess the meaning, but the plain meaning suggests they are adding in code that is deprecated and should, therefore, be removed from the code.
Tom Boutell explains some features that are hidden in his pkToolkitPlugin plugin for Symfony:
* The pkHtml class. Many projects allow users to edit content via a rich text editor. And we all know what happens if the user pastes a Word document in there: the styles of the page wind up hopelessly munged. You can use striptags(), but that doesn’t clean up the CSS, so your page is still a mess.
A common workaround is to use FCK’s “paste as plaintext” mode, which thwarts attempts to paste rich text from another program. That works, after a fashion, but it’s frustrating for users. And none of the workarounds help if the user is actively trying to enter inappropriate HTML in a misguided attempt to re-style their site… then calling you to fix it for the 500th time.
HTML Tidy can do the job, but it has a reputation for being heavy and slow.
Or… you can just use pkHtml::simplify():
I am intrigued by Felix De Vliegher’s suggestion for a single filter that catches all of one’s exceptions in Symfony:
class ExceptionCatcherFilter extends sfFilter
{
public function execute($filterChain)
{
if (sfConfig::get(’app_exceptionCatcherFilter’)) {
try {
$filterChain->execute();
} catch (sfStopException $e) {
// This is an internally used symfony exception and shouldn’t be blocked
throw $e;
} catch (Exception $e) {
// Do something with the exception, other than just throwing it
}
} else {
$filterChain->execute();
}
}
}
Generally, I dislike this style of programming, where all errors are funneled through a central well. This style of programming is the one advocated by Anders Hejlsberg (inventor of the C# language):
There’s a bottom level exception handler around their message loop. That handler is just going to bring up a dialog that says what went wrong and continue. The programmers protect their code by writing try finally’s everywhere, so they’ll back out correctly if an exception occurs, but they’re not actually interested in handling the exceptions.
The throws clause, at least the way it’s implemented in Java, doesn’t necessarily force you to handle the exceptions, but if you don’t handle them, it forces you to acknowledge precisely which exceptions might pass through. It requires you to either catch declared exceptions or put them in your own throws clause. To work around this requirement, people do ridiculous things. For example, they decorate every method with, “throws Exception.” That just completely defeats the feature, and you just made the programmer write more gobbledy gunk. That doesn’t help anybody.
…It is funny how people think that the important thing about exceptions is handling them. That is not the important thing about exceptions. In a well-written application there’s a ratio of ten to one, in my opinion, of try finally to try catch. Or in C#, using statements, which are like try finally.
…In the finally, you protect yourself against the exceptions, but you don’t actually handle them. Error handling you put somewhere else. Surely in any kind of event-driven application like any kind of modern UI, you typically put an exception handler around your main message pump, and you just handle exceptions as they fall out that way. But you make sure you protect yourself all the way out by deallocating any resources you’ve grabbed, and so forth. You clean up after yourself, so you’re always in a consistent state. You don’t want a program where in 100 different places you handle exceptions and pop up error dialogs. What if you want to change the way you put up that dialog box? That’s just terrible. The exception handling should be centralized, and you should just protect yourself as the exceptions propagate out to the handler.
In contrast, I have always preferred the style advocated by James Gosling (inventor of the Java language), and the style preferred by Bill Venners, as articulated in this interview:
Bill Venners: I do catch exceptions in an outer loop sometimes. But most times my catch clauses tend to be spread around the program. I find that catch clauses usually have a natural home—the method that has enough contextual knowledge to know how to deal with the exception. How would you recommend people organize their catch clauses?
James Gosling: I tend to do catches much more frequently than Anders would have you do, because the knowledge of the situation is always fairly localized. When you try to open a file and it’s not there, you’re coping strategy is really determined by what you were going for. Some guy miles away isn’t going to know what to do. The code that tried to open the file knows what to do, whether it be trying a backup file, looking in a different directory, or asking the user for another filename.
Having one big catch clause on the outside really only works if your exception handling philosophy is simply to die. If you have an event loop, you can maybe cause that one event to just be tossed. If you have a plugin architecture, the enclosing environment could respond to a failure in the plugin by disabling it—like an app server deciding to disable a servlet if it sees failures. But if you’re not doing an event driven program or plugins, there isn’t an outside place where you can take big hunks of functionality and saw them off. On the other hand, typically you should have last ditch try catch blocks. If you’re writing a web server, for example, it’s a good thing to put a last ditch try catch block around processing a request. But pretty much all that a try catch block like that can do is blow the request away. There’s no ability to respond gracefully. There’s no ability to take account of local context to cope and adapt, which is really one of the key hallmarks of truly reliable software.
The key sentence is “Having one big catch clause on the outside really only works if your exception handling philosophy is simply to die.” Handling exceptions close to where they happen allows you to use variables that are within the current context to try to rescue the situation.
All the same, Felix De Vliegher’s idea is a wonderfully clean way to proceed with a Hejlsberg type of exception handling.
I previously mentioned that the worst thing about Symfony is how under-documented Propel is. I also notice that the situation as gotten better than it was in the spring of 2008, when I started using Symfony. There are more and more examples of how to do things, for instance, a Left Join:
$c = new Criteria();
$c->addJoin(PatientPeer::DOC_ID, DocPeer::ID, Criteria::LEFT_JOIN);
$this->patients = PatientPeer::doSelect($c);
All the same, in the future, I will probably use Doctrine. It is well documented.
Alvaro Videla thinks out loud about what design patterns are implemented in Symfony:
Some of the patterns involved in Symfony are:
* Front Controller
* Command
* Intercepting Filter
* Context Object
* Two Step View
* Helper Object or View Helper
* Table Data Gateway (i.e.: ArticlePeer.php)
* Row Data Gateway (i.e.: Article.php)
* Active Record
* Single Table Inheritance
There are also technical complexities in that you have to provision EBS storage before you use it, and if you need to resize then you have to take a snapshot and rebuild from that.
We would have had to build our own infrastructure management system. This would have to handle the starting and failover of EC2 instances, backups and provisioning additional storage. In order to have no downtime when storage was being re-provisioned, we would need a second instance to replicate the database on. Aside from the extra server costs, all of this would have taken development time away from our efforts of improving the product itself.
We had the choice of working on infrastructure that makes no difference to the customer experience (but which would have been technically interesting and fun to develop) verses tangible progress with our product:
With six years of experience running my own software company I can tell you that nothing we have ever done at Fog Creek has increased our revenue more than releasing a new version with more features. Nothing. The flow to our bottom line from new versions with new features is absolutely undeniable.
- Joel Spolsky
And that’s the hidden cost – development time – something that is particularly important for a startup. As Jeff Atwood says, “Hardware is Cheap, Programmers are Expensive“.
I think I stumbled upon this site last year, when I was first learning Symfony. At that time, the site was very rough. It is still in alpha, even now, but it looks like it has reached a point where it is useful. It converts SQL into the code needed for Propel.
So it converts this:
person.gender = ‘M’ AND (person.location IN (’Birmingham’, ‘Coventry’) OR person.location = ‘Manchester’) AND (person.enabled <> 0) AND person.age > 16
Into this:
$c = new Criteria();
$crit0 = $c->getNewCriterion(PersonPeer::GENDER, ‘M’);
$crit1 = $c->getNewCriterion(PersonPeer::LOCATION, array(’Birmingham’, ‘Coventry’), Criteria::IN);
$crit2 = $c->getNewCriterion(PersonPeer::LOCATION, ‘Manchester’);// Perform OR at level 1 ($crit1 $crit2 )
$crit1->addOr($crit2);
$crit3 = $c->getNewCriterion(PersonPeer::ENABLED, 0, Criteria::NOT_EQUAL);
$crit4 = $c->getNewCriterion(PersonPeer::AGE, 16, Criteria::GREATER_THAN);// Perform AND at level 0 ($crit0 $crit1 $crit3 $crit4 )
$crit0->addAnd($crit1);
$crit0->addAnd($crit3);
$crit0->addAnd($crit4);// Remember to change the peer class here for the correct one in your model
$c->add($crit0);
$result = TablePeer::doSelect($c);// This loop will of course need to be edited to work
foreach ($result as $obj)
{
//$val = $obj->getValue();
}
Very useful, since the worst thing about Symfony is how under-documented Propel is.
There is a reason why Symfony developers are switching en masse to using Doctrine as their ORM, and that reason is the fact that Propel is badly documented. I’ve been using Symfony/Propel for a year now, and this is the most coherent explanation I’ve yet found about creating OR statements:
It is not a mistake but how propel works. I also thought that writing code like yours I will get an OR but $c->addOr() is when you want to include a rule about the same database field. By default $c->add() will overwrite the previous rules if the first argument (the table field) is the same, thus $c->addOr will make an OR statement for this field. The same is true for $c->addAnd() but you thought it works correct because by default it uses AND between fields, but the purpose of $c->addAnd is when you define different criteria for the same field and you want them connected with and AND. Also why are you using Criterion object directly?
This summer I worked on a project where some other programmer had used the Context object in the model classes. This caused ridiculous problems. For instance, to run the command line tools (such as “symfony propel:build-model”) I had to hard-code the loading of a context object into the core classes – what an ugly hack!
So I was intrigued to read of the problems that the Context object can cause in your form classes, and how dependency injection gives us an easy way to avoid needing the Context object.
You might read that and think “woah, this is getting complicated!” but we’re not talking about dependency injection containers here, we’re simply saying that you can make your form object depend on something to run. The thing it depends on should not be the context singleton, it should be the minimum thing that the form needs to operate correctly – which in this case, is a user object that supports credentials.
…The test here is where we are making this form “dependent” on a user object. In this case we are insisting that the object is an instance of sfUser, which you may argue is tying us in to symfony again, but you could use any test here to ensure that the object will have the necessary functionality you need, maybe check for the existence of a “hasCredential()” method for example.
When writing a test for this form class, we now only need to instantiate a user object and load it with some credentials – much easier than doing the same thing and locking into a context singleton. There may be other times when this form could be useful in a lightweight environment, where you can get speedy access to a user object but don’t want the overhead of the symfony context – you might not think of one now, but it’s best to code this way and you’ll have less reasons to kick yourself further down the line.
How to redirect to original destination after login in Symfony. I recall this information was way too hard to find when I first went looking for it:
on first hit to your login action, store referer to the user session:
if(!$this->getUser()->hasParameter(’referer’))
{
$this->getUser()->setParameter(’referer’,$this->getRequest()->getReferer();
}and then when login succedes, redirect user to stored referer with:
$this->redirect($this->getUser()->getParameter(’referer’);