symfonynerds.com

Nerds who love the symfony-project

Archive for the ‘Symfony MVC’ Category

In Symfony, how big should a module be?

How big should a module be in Symfony? I’ve been re-thinking this issue in light of what I’ve been reading about RESTful architectures.

For awhile now, Symfony has been moving toward enabling a RESTful architecture. As Fabien Potencier wrote a year ago:

The sfRequestRoute is the first step towards a RESTful architecture.

See also this talk he gave.

What is a RESTful architecture and what is it useful for? The best answer to both questions comes from the book Restful Web Services by Leonard Richardson and Sam Ruby (published May of 2007). Though the phrase “RESTful” actually comes from Roy Fielding’s Phd dissertation, I think it is reasonable to say that the popularization of the term come from what those 2 men wrote on their blogs in 2006 and 2007, and then from the book they jointly produced.

Their writing arose at first in opposition to what had become known as “Web Services”. That style of architecture focused on delivering XML via an HTTP request and then interpreting the payload via protocols that had become horribly complex. For an excellent parody, read “The S stands for Simple” by Pete Lacey, which creates an imaginary conversation between a developer and an evangelist for the SOAP protocol. Lacey’s criticism is the same one that Richardson and Ruby are making:

Dev: Hrrm. And what happens if I move the service to a different endpoint? Do I get a 301 back?

SG: No. SOAP doesn’t really use HTTP response codes.

Dev: So, when you said SOAP uses HTTP, what you meant to say is SOAP tunnels over HTTP.

SG: Well, ‘tunnel’ is such an ugly word. We prefer to say SOAP is transport agnostic.

Dev: I’ll note that your entire industry is built around ambiguous, sometimes erroneous, and definitely not standardized specifications. In fact, the SOAP and WSDL specs are just W3C Notes, not even working drafts.

Against this bloated, overly-complicated style, Richardson and Ruby set out to remind people what made the Web such a big success in the first place (Preface, page xiii):

It may seem strange to claim that the Web’s potential for distributed programming has been overlooked. After all, this book competes for shelf space with any number of other books about web services. The problem is, most of today’s “web services” have nothing to do with the web. In opposition to the Web’s simplicity, the espouse a heavyweight architecture for distributed object access, similar to COM or CORBRA. Today’s “web service” architectures reinvent or ignore every feature that makes the Web successful.

It doesn’t have to be that way. We know the technologies behind the Web can drive useful remote services, because those services exist and we use them every day. We know such services can scale to enormous size, because they already do. Consider the Google search engine. What is it but a remote service for querying a massive database and getting back a formatted response? We don’t normally think of web sites as “services,” because that’s programming talk and a web site’s ultimate client is a human, but services are what they are.

Every web application - every web site - is a service. You can harness this power for programmable applications if you work with the Web instead of against it, if you don’t bury its unique power under layers of abstraction. It’s time to put the “web” back in “web services”.

The features that make a web site easy for a web surfer to use also make a web service API easy for a programmer to use. To find the principles underlying the design of these services, we can just translate the principles for human-readable web sites into terms that make sense when the surfers are computer programmers.

They then summarize some of the “weaknesses” in the HTTP protocol, and they point out that these weaknesses are really strengths. They reference what Clay Shirky has written on this subject:

If it were April Fool’s Day, the Net’s only official holiday, and you wanted to design a ‘Novelty Protocol’ to slip by the Internet Engineering Task Force as a joke, it might look something like the Web:

The server would use neither a persistent connection nor a store-and-forward model, thus giving it all the worst features of both telnet and e-mail.

The server’s primary method of extensibility would require spawning external processes, thus ensuring both security risks and unpredictable load.

The server would have no built-in mechanism for gracefully apportioning resources, refusing or delaying heavy traffic, or load-balancing. It would, however, be relatively easy to crash.

Multiple files traveling together from one server to one client would each incur the entire overhead of a new session call.

The hypertext model would ignore all serious theoretical work on hypertext to date. In particular, all hypertext links would be one-directional, thus making it impossible to move or delete a piece of data without ensuring that some unknown number of pointers around the world would silently fail.

The tag set would be absurdly polluted and user-extensible with no central coordination and no consistency in implementation. As a bonus, many elements would perform conflicting functions as logical and visual layout elements.

HTTP and HTML are the Whoopee Cushion and Joy Buzzer of Internet protocols, only comprehensible as elaborate practical jokes. For anyone who has tried to accomplish anything serious on the Web, it’s pretty obvious that of the various implementations of a worldwide hypertext protocol, we have the worst one possible.

Except, of course, for all the others.

The problem with that list of deficiencies is that it is also a list of necessities — the Web has flourished in a way that no other networking protocol has except e-mail, not despite many of these qualities but because of them. The very weaknesses that make the Web so infuriating to serious practitioners also make it possible in the first place. In fact, had the Web been a strong and well-designed entity from its inception, it would have gone nowhere. As it enters its adolescence, showing both flashes of maturity and infuriating unreliability, it is worth recalling what the network was like before the Web.

My thoughts about a RESTful design in Symfony need to be qualified: I’m mostly talking about architecture for robot-consumed APIs. The architecture I’m thinking of is not necessarily one that you would need to adopt for a site that is meant for humans. Richardson and Ruby make a distinction between the “human web” and the “programmable web”, that is, sites that are meant to be seen by humans, versus sites that are mostly devoured by software robots that need to consume data to fulfil whatever function they’ve been programmed to do. From page 1:

When you - a human being - want to find a book on a certain topic, you probably point your web browser to the URI of an online bookstore: say, http://www.amazon.com/

You’re served a web page, a document in HTML format that your browser renders graphically. You visually scan the page for a search form, type your topic (say, “web services”) into a text box, and submit the form. At this point your web browser makes a second HTTP request, to a URI that incorporates your topic…

The web server at amazon.com responds by serving a second document in HTML format. This document contains a description of your search results, links to additional search options, and miscellaneous commercial enticements. Again, your browser renders the document in graphical form, and you look at it and decide what to do from there.

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.

On most of the Symfony projects that I’ve worked on so far, the tendency has been to have one module for one model. There have been some variations on that theme, but that has been the trend. For instance, to handle the users of a site, we might have a database table called sf_guard_user_profile, and then a model called sfGuardUserProfile, and a module called “user”, and in that module we might put every action that has anything to do with the model - look at all users, look at frequent users, look at a particular user, send a message to a user, update the user, show the user’s dashboard, show the user’s finances. On the MyBailiwick project we had huge modules - the user module had 40 public functions and maybe a dozen protected or private ones.

Building a RESTful API calls for a different design. Following the advice or Richardson and Ruby, we might end up with lots of very small modules, each of which have only 4 or 5 functions, corresponding to these actions:

read all (list all of a type)

read one (show one of a type)

write (create)

update

delete

Richardson and Ruby feel strongly that the method name (the action to be undertaken) should be one of the HTTP verbs:

GET

POST

PUT

DELETE

This is what Richardson and Ruby refer to as the “uniform interface” of HTTP. Unlike the ever changing, and confusing, interface of protocols such as SOAP or WSDL, HTTP has a simple interface, made up of 7 verbs, and the interface is not likely to change.

In a well-designed RESTful architecture, the method action does not go in the URL, it goes in the HTTP headers. In the course of the book, Richardson and Ruby set out to create an API for a site that allows people to upload and create their own maps. Here they talk about creating the service that will allow the site to create new user accounts (from page 149):

Expose a subset of the uniform interface

This is the first new step. I skipped it when designing read-only resources, because there was nothing to decide. By definition, read-only resources are the ones that expose no more than the HTTP methods GET, HEAD and OPTIONS. Now that I’m designing resources that can be created and modified at runtime, I also have PUT, POST and DELETE to consider.

Even so, this step is pretty simple because the uniform interface is always the same. If you find yourself wishing there were more HTTP methods, the first thing to do is go back to step two, and try to split up your data set so you have more kinds of resources. Only if this fails should you consider introducing an element of the RPC style by making a particular resource support overloaded POST.

To reiterate the example from Chapter 5: if you have resources for “readers”, and resources for “published columns,” and you start thinking “it sure would be nice if there was a SUBSCRIBE method in HTTP,” the best thing to do is to create a new kind of resource: the “subscription”. As HTTP resources, subscriptions are subject to HTTP’s uniform interface. If you decide to forgo the uniform interface and handle subscriptions through overloaded POST on your “reader” resources, defining the interface for those resources becomes much more difficult.

I can decided which bits of the uniform interface to expose by asking questions about intended usage:

1.) Will clients be creating new resources of this type? Of course they will. There’s no other way for users to get on the system.

2.) When the client creates a new resource of this type, who’s in charge of determining the new resource’s URI? Is it the client or the server? The client is in charge, since the URI is made up entirely of constant strings (https://maps.example.com/user/) and variables under the client’s control ({user-name}).

From those two questions I get my first result. To create a user account, a client will send a PUT request to the account’s URI. If the answer to the second question was “the server’s in charge of the final URI,” I’d expect my clients to create a user by sending a POST request to some “factory” or “parent” URI.

Again, this advice is aimed at API’s that are designed to be consumed by computers, not humans. But I like the idea of designing my code so that it could function, without much change, for dual use, as both an architecture for a human readable website, and also for an API for computers. This style of architecture would be a big change for me. Right now I’m working to refactor the code on WP Questions. As I look through the modules, I see that many of them could be broken apart into smaller modules, each with just 4 or 5 public functions: read, write, update delete. Though I worry about ending up with too many modules, I like the idea of each module being simple and focused. And RESTful.

  • 4 Comments
  • Filed under: Symfony MVC
  • Worker classes in Symfony

    I’ve been thinking about the fact that the engineers at Google view static classes as terrible things. My own code has an unfortunate number of static classes. Mostly this is because I am not sure where to put some of the code. For instance, on every project I have a few methods that format output. Some of these methods are the same on every project, so I hate to put them in the action code. Where else? Output formatting obviously does not belong in the model classes. What about methods for formatting dates, methods which I use in action code in multiple modules? It is easiest to put this into a class of static methods. Then I can call it from everywhere.

    Another approach would be to add methods to the parent class. The parent of all action classes is sfActions. I’ve thought about editing sfActions, but I hate the idea of editing a core class of Symfony. I’ve also thought about creating a child class of sfActions, adding my methods there, and then having all of my action classes inherit from that. This is probably the best way to go, but I admit to a certain laziness. At some point I plan to write my own custom generation classes, which would make this easier. For now I tend to rely on the auto-generate code. Also, there are some good arguments against tall object trees. In his book Effective Java, Joshua Bloch suggests “Favor composition over inheritance.”

    Given these concerns, I was interested to read this article about worker classes in Symfony. They list these advantages:

    Advantages of worker classes

    1. actions could be shrinked huge in size

    2. worker classes are more decoupled from the rest of symfony and could be tested better

    3. you can replace the content of an worker method without breaking actions

    This is a step away from the problems of static classes. It provides a place in the object hierarchy where this code might legitimately belong. The engineers at Google suggested that most static methods should really belong to one of their own parameters. I can imagine worker classes as a way of making this happening, without bloating up the owning class.

    A follow-up article looks at the interface changes that worker classes allow. These changes should allow better long-term maintainability and better testing. I especially like the idea of removing all ORM specific code from my action classes.

    The action (or template) does not process anymore with a concrete ORM model. With the help of the proxy class, we can change the underlying model layer without breaking anything in the action. By providing a well defined interface, the proxy class manages how a model could be modified and accessed.

    At this point, you should understand the reason for all those changes. It may look like a huge overhead for just retrieving some data out of the model. But in our case it was a precondition for our global architecture.

    Our models and our main business logic is partly served by and processed in SOA applications (there we use Propel and i hope in some near days also Doctrine). I implemented a mechanism, which allows worker classes to access those SOA applications very easily. They are fetching the serialized data from those applications, hydrate them into proxy classes and provide them to the rest of the project.

    …In this way, action code is really short, it is completely decoupled from the logic how the model is originally handled and it works quite well. If we decide to change something in our architecture some day, we only have to change our worker and proxy classes. The rest of the project will not notice those changes, as it should be in a layered architecture.

    Sure, this step is nothing for small applications. But when your project grows and grows, the number of requests in a second turns from dozens to hundreds, then you’ll be thankful, if your project provides this approach.

    I will probably be adopting some of this technique for my own current project.

    Darren Hoyt and I rolled out a new website yesterday. WP Questions is a place for WordPress developers to go when they have questions so urgent that they are willing to pay money to get an answer. We built the site using Symfony, and I’d like to use this site to talk about the situations where I think Symfony makes a great choice as a development platform.

    First, understand our goals. We needed to create a site that allowed questions to be posted, money to be taken, answers to be given, and money dispersed to the person who had offered the most useful answer. Darren Hoyt did a good job of summarizing the goals of the site.

    Right now we are listening to feedback and fine-tuning the site. Once we feel we have fixed all the bugs and added all the needed features, we plan to roll out an identical site for each of the major technologies: Java, Ruby, Rails, Symfony, Cake, Drupal, .NET Oracle, SQL, Javascript, etc.

    So what do we need in our development platform?

    1.) We can not guess the future of our data storage so we need database abstraction that keeps SQL out of our code.

    2.) We know the structure of our data will evolve, so we need an ORM that can mask the changes.

    3.) We know the designs will evolve and multiply even as the data schema evolves, so we need a clean MVC architecture that allows us to correctly observe a separation of concerns.

    4.) We know that if we are successful we will eventually need to hire other programmers, so we need a well-documented framework that other programmers know, preferably one that is open source.

    5.) We need to maintain the code base even as we scale up to running 100 sites, so we need a framework that allows us to run 100 sites off a single installation.

    So what should we use?

    A few months ago it was suggested that we use WordPress to develop the site. I think this is clearly a bad idea. WordPress has a fairly rigid database structure. A developer can add new database tables to any WordPress installations, but establishing relationships between the new tables and the core tables is always a bit of a hack. And WordPress engages in some practices that I regard as extremely questionable, such as storing config data in the database and using fields in the database to store formatted text that needs to be drawn out and parsed for data - data storage inside of data storage.

    We could have also started with forum software like phpBB and then hacked it to add in the other features that we wanted. But again, it would be an uphill struggle against a database structure that makes too many assumptions about what we need, and which offers us few tools to evolve the structure over time. And, personally, I find their template system a pain to edit.

    Last month I complained about the prominence of Drupal. The comments in that thread show that Drupal has some very strong supporters. However, Drupal started life as a CMS, and still shows some traces of that, in terms of assumptions about database structure. Also, its files live within the directory of the server that is made available to the public on the web, something I regard as a security risk. Karl made a good point in a comment in that thread:

    Interesting here is that I looked at drupal, but choose not to use it, instead, Symfony was the choice. The two biggest reasons was 3rd party integration with quickbooks and scalability, we were afraid that drupals datamodel would cause us headaches at the end.

    I like the way that James Herrmann summed things up at the end:

    What are the questions asked that lead to the answer of ‘Symfony’, ‘Cake’, or ‘Solar’? I have a feeling they would entail infinite extensibility, unit testing, bridging with other libraries, optimization and security, to name a few.

    Clearly, using a CMS is a bad idea when you know you’ll need a maximum of flexibility in the future. But why use Symfony? Why not use one of the other frameworks? Grails offers a clean architecture, a great plugin system, a highly productive dynamic environment. Groovy, and the JVM, is somewhat faster than PHP, so it offers a speed boost which might be important when we need to scale up. I’ve written enough Groovy code that I could probably write the app in Grails if I wanted to. So why not? My reasons here have to do with the overall eco-systems that surround the 2 languages. There is an abundant supply of PHP programmers. More importantly, the sysadmins I know are comfortable with Linux, Apache and PHP, but not with Tomcat. In the bad old days, the whole world of Java was geared toward Fortune 500 companies with big budgets. The frameworks were as verbose as the underlying language. The idea of dynamic languages and lightweight frameworks is relatively new to the world of the JVM. PHP, by contrast, has been stable for 10 years now, and it has a huge following.

    There are, of course, a hundred other technologies I might have considered, but I am limited to the ones I know well.

    Symfony is going to allow us to grow and evolve the database structure while keeping the code clean. I’ll give you an example. On our Top Winners page we offer a few ways of sorting. The page shows the users, their name, their image and how much they’ve won. I must draw the data out of these 2 tables:

    sf_guard_user_profile:
    _attributes: { phpName: sfGuardUserProfile }
    id: ~
    user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: true }
    status: { type: varchar(255), required: false }
    first_name: { type: varchar(255), required: false }
    last_name: { type: varchar(255), required: false }
    email: { type: varchar(255), required: false }
    url: { type: varchar(255), required: false }
    biography: { type: longvarchar, required: false }
    created_at: ~
    updated_at: ~
    cash_total: { type: float, required: false }
    image: { type: VARCHAR, size:255 }
    secret_signup_key: { type: VARCHAR, size:255 }

    answer:
    id: ~
    user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: false }
    question_id: { type: integer, foreignTable: question, foreignReference: id, required: false }
    image: { type: varchar(255), required: false }
    description: { type: longvarchar, required: false }
    status: { type: varchar(255), required: false }
    score: { type: integer, required: false }
    prize_amount_paid_for_this_answer: { type: float, required: false }
    created_at: ~
    updated_at: ~

    I need to create a JOIN. There is no foreign key relationships between these 2 tables, so the automatically generated Propel classes do not have any JOIN methods. I prefer to handle this by creating a database view,

    CREATE VIEW answers_totals_users AS
    SELECT answer.*,
    COUNT(question_id) as questionTotal,
    SUM(prize_amount_paid_for_this_answer) as prizeTotal,
    sf_guard_user_profile.first_name, sf_guard_user_profile.last_name,
    sf_guard_user_profile.image AS userImage
    FROM answer, sf_guard_user_profile
    WHERE answer.user_id=sf_guard_user_profile.user_id
    GROUP BY answer.user_id

    and then I add it to schema.yml as if it was a real database table:

    answers_totals_users:
    id: ~
    user_id: { type: integer, foreignTable: sf_guard_user, foreignReference: id, required: false }
    question_id: { type: integer, foreignTable: question, foreignReference: id, required: false }
    image: { type: varchar(255), required: false }
    description: { type: longvarchar, required: false }
    status: { type: varchar(255), required: false }
    score: { type: integer, required: false }
    prize_amount_paid_for_this_answer: { type: float, required: false }
    prizeTotal: { type: float, required: false }
    questionTotal: { type: integer, required: false }
    created_at: ~
    updated_at: ~
    first_name: { type: varchar(255), required: false }
    last_name: { type: varchar(255), required: false }
    userImage: { type: VARCHAR, size:255 }

    Then I run the “symfony propel:build-model” command, and now I have a model class that selects against this JOIN as if it was a single table. This leaves my action code looking simple and clean:

    $limit = $request->getParameter(’limit’);
    if (!$limit) $limit = 25;
    $c = new Criteria();
    $c->setLimit($limit);
    $c->add(AnswersTotalsUsersPeer::PRIZETOTAL, 0, Criteria::GREATER_THAN);
    $c->addDescendingOrderByColumn(AnswersTotalsUsersPeer::PRIZETOTAL);
    $this->listOfTopWinners = AnswersTotalsUsersPeer::doSelect($c);

    I started to think of a site such as this one some years ago, when I first used Experts Exchange. I was frustrated that Experts Exchange took my money, yet none of the money went to the people who were helping me. I wanted a site where I could give money directly to the people answering my questions. My ideas about this site have become more clear over time, and no doubt 6 months from now I’ll have even more clarity about how this site/software can be useful to people. Likewise, as we get more feedback from our users we will continue to add new features, and offer more information. They’ll be a need for more JOINs and sometimes new database tables. A framework like Symfony assumes a changing database structure, it is set up to help a developer deal with those changes, and in this it is different from the CMSs that assume they know what kind of site you are building. Symfony, therefore, offers an attractive set of features for developing our site/software over the long term. It is the ideal development platform for us.

  • 6 Comments
  • Filed under: Symfony MVC
  • This tip is a quick one for newbies. The Symfony book has some great tips as to when you would want to use a Symfony forward, vs a Symfony redirect. This quick post will show you the difference between the two and give you some guidelines to know when to use redirect or forward.

    So what’s the main difference?

    Symfony Redirect: This simply does a HTTP header(”location: “)
    Symfony Forward:
    This is complete custom code that comes with the Symfony framework that forwards you within the Symfony application.

    Use Symfony Forward if:

    • If the action needs to forward a call to another action
      This will mean you can keep all the action class’ objects in scope and still have access to them
    • You want to forward the user to an action within the application, and keep it transparent to the user.
      From a users perspective - the displayed URL stays the same.

    Use a Symfony Redirect if:

    • You need to go to an external website (http://google.com for example)
    • You don’t want the user to re-submit a form (if you are doing a form POST)
      It is generally good practice to do a redirect after a POST to ensure the user does not re-submit the form.

    Conditional Forwarding/redirect
    Quite often you need to forward or redirect if a condition has been met. Be sure to checkout the other Symfony functions that help you do this (forwardIf(), forwardUnless(), forward404If(), forward404Unless(), redirectIf(), and redirectUnless())

    What about AJAX calls?
    You can check if a HTTP request is an AJAX call before deciding what to do with it by calling calling  $request->isXmlHttpRequest() in your actions class. Once you have done this you can choose what you want to do; redirect or forward.

    We came across an interesting problem today when setting up an application we’d built earlier in a fresh dev environment to add some features…

    Because we’re big fans of MySQL Workbench we made our initial schema changes there, generated the SQL to update the DB, then used a symfony propel:build-schema to generate an updated schema.yml followed by a symfony propel:build-model to update the model…

    All good so far, until I began work on the first change and tried to fire off the task I’d just written…

    Fatal error: Class 'BaseSMMConfig' not found in /usr/local/projects/smm/lib/model/SMMConfig.php on line 3

    After some looking around, I realised my base class was called BaseSmmConfig - spot the problem? Yes, the ‘mm’ was lower case, while my class was looking for ‘MM’ in capitals…

    So what caused this?

    The application had originally been created by writing the schema.yml file (including the phpName being specified) then doing a symfony propel:build-all to create the DB and the model together. This is fine as the capitalisation used in the hand written schema.yml flowed through to the model. When I had done the reverse, creating a schema.yml from the DB, all it has to go on is the names of the tables, using camel case to identify where an underscore exists in the table name, so the ’smm_config’ table becomes SmmConfig in the schema.yml and model, not SMMConfig as originally typed. Because your extendable model classes don’t get updated (so as not to overwrite your changes) your app then breaks down.

    So the lesson:

    • Always observe strict camel case if you specify phpName
    • Don’t specify it, let it be generated
    • Work backwards by creating your DB first - using Workbench makes this an attractive option, saves you drawing up the schema later…

    If you are defining your schema.yml and have a field that is a decimal value, you will find you will need to somehow pass through the precision (maximum number of digits to the left of the point) and the scale (total number after the decimal point). The documentation for the syntax of this is quite poor.
    For all those that want to know, in Symfony 1.0 this is how you would define a decimal:

    my_decimal: { type: decimal, size: 8,3 }

    For Symfony 1.1+, the Syntax is a bit different:

    my_decimal:
          type: decimal
            size:    8
            scale:   3

    Where 8 is the precision and 3 is the scale. Hope this helps.

    Symfony application configuration can be configured for each application in the app.yml file. One of they key problems with this is if you want an end-user to be able to change some of this application configuration, they can’t. You would need to do that for them.

    A good way to fix this is to store your applications configuration in the database. This comes with a performance cost (extra calls to your database) - so its up to you to decide if this is the most efficient solution for you.

    Here is an outline on how to get started building your application’s config in the database.

    Step 1: Define your model
    Create the columns you want to store for your application config. In this instance, we are just going to store name and value pairs (ie Attribute & Value). Here is a sample below:

    propel:
      #Application configuration table
      my_app_config:
        _attributes:                { phpName: MyAppConfig }
        id:                         { type: integer, required: true, primaryKey: true, autoIncrement: true }
        attribute:                  { type: varchar(255) }
        value:                      { type: varchar(255) }
    ...

    Once you have finished that, go ahead and build your model

    Step 2: Extend Your MyAppConfig class
    So the next step is for us to make it easy to access application configuration. For us to do this, go to your lib/model/MyAppConfig.class.php and extend your base class as follows:

    <?php
    class MyAppConfig extends BaseMyAppConfig
    {
     
      /**
       * Returns a value of an attribute string for my app's config table
       * @param string attribute name
       * @return string The value of that attribute
       * @author eHabib
       */
    	public function lookupValueFromAttribute($attribute){
      		$c = new Criteria();
      		$c->add(MyAppConfigPeer::ATTRIBUTE, $attribute);
      		$result = new MyAppConfig();
      		$result = MyAppConfig::doSelectOne($c);
    		return ($result->getValue());
    	}
    }

    Step 3: Use it!
    Let’s say that in our database we have the following attribute/value paris:

    Attribute: app_support_email, Value: myemail@mydomain.com
    Attribute: app_base_url, Value: http://whatever

    You could access this data in your code by doing this:

    $myConfig = new MyAppConfig();
    $appEmail = $smyConfig->lookupValueFromAttribute("app_support_email");
    $appURL = $smyConfig->lookupValueFromAttribute("app_base_url");
    ...
    echo $appEmail.",".$appURL; //lets print it

    That’s it!

    Step 4: Configure it via your front-end
    The last step (if you wish) is to allow the end-user to update the value of these fields. To do this, you can build a form to update these fields, or use Symfony’s admin generator.

    In previous Symfony versions it was quite difficult and painful to link your applications together (eg frontend and backend).

    Yesterday the Symfony crew posted a tutorial on how easy it is in Symfony 1.2. In essence, its a simple config change and a change to your sfApplicationConfiguration class.

    However, this method does still require an absolute hard-code of your application URL within your class (or you could put it in a config setting in your app.yml and read it off there). Even though it required some hard-coding, it still is much simpler and easier to use than Symfony 1.0 and 1.1 methods.

    For more information - check out the Symfony blog post.

    Symfony nerds tip: To avoid hard-coding as much as possible, you could in your app.yml define your application URL’s for each environment (eg. DEV, TEST and PROD). Once you have, in your application configuration class (which extends sfApplicationConfiguration), you could read the config variable for your application URL, but automate that via sfConfig::get(’sf_environment’). And depending on what environment you are in, you will select the application URL that corresponds to that environment.

    Lately I’ve been working on some Symfony batch components to load/export data into and out of a database. If you are looking for a way to send emails from your Symfony batch scripts there are two ways.

    1) Use An Action
    It is possible to use a pre-defined action within a module for sending emails. You can, for example do this:

    sfContext::getInstance()->getController()->sendEmail('module', 'mySendEmailAction');

    Where you have a module called ‘module’ and an action within that called ‘mySendEmailAction’. You do however, run into issues when you want to pass paramaters across from your batch script to your action. I havent figured that one out yet - so if you know,  let us know!

    The important thing to note with this option is that you will need to enable the is_internal setting in module.yml of your module.  The is_internal paramater allows you to restrict access to your action so that it only takes internal calls. To change this so that outside components (eg batch) can call your action, set is_internal to false. If you dont do this, you might get an error like this:

    Uncaught exception ’sfConfigurationException’ with message ‘Action”mySendEmailAction” from module “module” cannot be called directly’ in /usr/share/php/symfony/controller/sfController.class.php:237

    2) Directly use sfMail
    The other, simpler option is to use sfMail directly. Within your Symfony batch script, just write your own custom method to send mail.

    function sendEmail(){
      // class initialization
      $mail = new sfMail();
      $mail->initialize();
      $mail->setMailer('sendmail');
      $mail->setCharset('utf-8');
     
      // definition of the required parameters
      $mail->setSender('webmaster@my-company.com', 'Me');
      $mail->setFrom('info@my-company.com', 'My Company');
      $mail->addReplyTo('webmaster_copy@my-company.com');
      $mail->addAddress('test@test.com');
      $mail->setSubject('Those Symfony nerds are hot');
      $mail->setBody('Well.. they think they are');
      $mail->send();
    }

    Do you know of any other or better ways? Let us know! I’m not too sure how Symfony 1.1 tasks handels this, that will be another blog post in a few months time…

    I am working on an interesting project where I have been given the task of creating a web interface that allows an authenticated and authorised user to conduct specific types of search on a huge data set.

    The data set begins as flat text logs which are transformed and loaded into a normalised schema - which was designed well before I got involved.  So, I have been very impressed by the way that propel and creole have consistently reverse engineered the schema and built a reliable model.

    This is not a post about Propel or Creole but I thought to put this into context since I have been given a development specification that requires me to present data on a browser in a manner different to the way in which it is ordered and layed out in the database schema.

    So - consider a table that has the following structure:

    id (auto increment unique id)
    my_date (of type date)
    my_date_as_int (a conversion of date to int eg 2008-08-06 would be 20080806)

    The insertion of dates into the above fields is not ordered - so id 1 may have an older date than id 2 and so on…for example:

    id my_date_as_int my_date
    1 20080602 2008-06-02
    2 20080724 2008-07-24
    3 20080723 2008-07-23
    4 20080411 2008-04-11
    5 20080412 2008-04-12

    My task was to create a “drop down” select tag that showed the above sorted in an ascending order by the date field.

    Step 1.  Create a __toString method to return the date field as opposed to the Id.

    public function __toString()
    {
    return $this->getMyDate();
    }


    Step 2.  Create a custom method in the relevant Peer class to get a sorted list:

    public static function getSortedDate()
    {
    $c = new Criteria();
    $c->addAscendingOrderByColumn(DatePeer::MY_DATE_AS_INT);
    $rs = DatePeer::doSelect($c);
    return $rs;
    }

    As you can see, I choose to sort by the integer representation of the date field, but you can use the MY_DATE field in the same manner.

    Step 3.  Create a drop down select_tag in your view.

    There are two options here.

    Option 1.  Standard form name, value pairs being the date and id fields respectivey.

    <?php echo object_select_tag('', 'getMyDate', array (
      'related_class' => 'Date',
      'peer_method' => 'getSortedDate',
      'include_blank' => true,
    )) ?>


    Option 2.  Form name, value pairs being the my_date and the my_date_as_int fields respectivey.

    <?php
      echo select_tag('', 
       objects_for_select(DatePeer::getSortedDate(), 'getMyDateAsInt','getMyDate'),
       array('id'=>"this_date",'name'=>"this_date"))
    ?>

    That is it! The view then renders a drop down select that is constructed firstly by a call to the getSortedDate method, which in turn returns an array of sorted items - each of which is shown in the drop down using the __toString method to convert from an id to the date.