<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/atom10full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" xml:lang="en">
  <title>Posts tagged "symfony" from Mark Ng</title>
  <link rel="alternate" href="http://www.markng.co.uk/blog/tag" />
  <id>http://www.markng.co.uk/blog/tag</id>
  <updated>2008-05-07T21:11:08Z</updated>
  <author>
    <name>Mark Ng</name>
  </author>
<link rel="self" href="http://feeds.feedburner.com/markng-symfony" type="application/atom+xml" /><entry>
  <title>Feedshaver - categorize your RSS feeds using opencalais</title>
  <link rel="alternate" href="http://feeds.feedburner.com/~r/markng-symfony/~3/285640811/feedshaver---categorize-your-rss-feeds-using-opencalais" />
  <updated>2008-05-07T21:11:08Z</updated>
  <author>
    <name>Mark</name>
  </author>
  <id>74</id>
  <summary type="text">The application I built for the telegraph developer weekend (which won second prize) is live on the [...]</summary>
  <content type="html">&lt;p&gt;The application I built for the telegraph developer weekend (which won second prize) is &lt;a href="http://feedshaver.com/"&gt;live on the internet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://feedshaver.com"&gt;Feedshaver&lt;/a&gt; is an application written in &lt;a href="http://www.symfony-project.org/"&gt;symfony&lt;/a&gt; that utilizes Reuters &lt;a href="http://www.opencalais.com/"&gt;OpenCalais&lt;/a&gt; service to automatically tag RSS feeds and allow you to follow only certain subjects in a feed (or all of the feeds in the system).  Eventually, I intend on adding feed groups, the ability to opt out of subjects instead of opt in and many other things, but for now, a slightly tidied version of the app I built in 4 hours is live.  Hopefully, it'll be of use to someone.&lt;/p&gt;

&lt;p&gt;Oh, I might even get a design for it, too.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/markng-symfony/~4/285640811" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://www.markng.co.uk/blog/2008/05/07/feedshaver---categorize-your-rss-feeds-using-opencalais</feedburner:origLink></entry>
<entry>
  <title>Populating sfSimpleBlogPlugin from RSS</title>
  <link rel="alternate" href="http://feeds.feedburner.com/~r/markng-symfony/~3/248007892/populating-sfsimpleblogplugin-from-rss" />
  <updated>2008-03-05T21:03:21Z</updated>
  <author>
    <name>Mark</name>
  </author>
  <id>71</id>
  <summary type="text">Finally, I've moved my personal site to Symfony.  I've been using the framework extensively professi[...]</summary>
  <content type="html">&lt;p&gt;Finally, I've moved my personal site to &lt;a href="http://www.symfony-project.org/" title="symfony Web PHP Framework"&gt;Symfony&lt;/a&gt;.  I've been using the framework extensively professionally for a bit more than a year.  I decided to use &lt;a href="http://trac.symfony-project.com/wiki/sfSimpleBlogPlugin" title="sfSimpleBlogPlugin - symfony - Trac"&gt;sfSimpleBlogPlugin&lt;/a&gt; to handle the blogging requirements on the site.  I could have spent a while fiddling with databases to get the old data from my site off, but instead I decided to follow a different route by pulling all of my data from my old RSS feed.&lt;/p&gt;

&lt;p&gt;Symfony provides the excellent &lt;a href="http://trac.symfony-project.com/wiki/sfFeed2Plugin" title="sfFeed2Plugin - symfony - Trac"&gt;sfFeed2Plugin&lt;/a&gt; for producing and parsing various feed formats.  I used this outside of the controllers in a batch task to do import my old data in.  Here is the code :&lt;/p&gt;

&lt;pre&gt;
  &amp;lt;?php

  // set up a the symfony environment for batch 
  define(&amp;#x27;SF_ROOT_DIR&amp;#x27;,    realpath(dirname(__FILE__).&amp;#x27;/..&amp;#x27;));
  define(&amp;#x27;SF_APP&amp;#x27;,         &amp;#x27;frontend&amp;#x27;);
  define(&amp;#x27;SF_ENVIRONMENT&amp;#x27;, &amp;#x27;prod&amp;#x27;);
  define(&amp;#x27;SF_DEBUG&amp;#x27;,       false);

  require_once(SF_ROOT_DIR. DIRECTORY_SEPARATOR.&amp;#x27;apps&amp;#x27; .DIRECTORY_SEPARATOR.SF_APP. DIRECTORY_SEPARATOR.&amp;#x27;config&amp;#x27;. DIRECTORY_SEPARATOR. &amp;#x27;config.php&amp;#x27;);

  sfContext::getInstance();

  // get the RSS
  $feed = sfFeedPeer::createFromWeb(&amp;#x27;http://www.markng.co.uk/rss.php?c=blog&amp;#x27;);

  // delete all posts in the posts table (remove this if not doing an initial import)
  sfSimpleBlogPostPeer::doDeleteAll();

  // get items from the feed and then loop through and save
  $items = $feed-&amp;gt;getItems();
  foreach ($items as $key =&amp;gt; $post) 
  {
    $importPost = new sfSimpleBlogPost();
    $importPost-&amp;gt;setAuthorId(1);
    $importPost-&amp;gt;setTitle($post-&amp;gt;getTitle());
    $importPost-&amp;gt;setStrippedTitle($post-&amp;gt;getUniqueId());
    $importPost-&amp;gt;setContent($post-&amp;gt;getDescription());
    $importPost-&amp;gt;setIsPublished(1);
    $importPost-&amp;gt;setAllowComments(1);
    $importPost-&amp;gt;setCreatedAt($post-&amp;gt;getPubDate(&amp;#x27;U&amp;#x27;));
    $importPost-&amp;gt;setPublishedAt($post-&amp;gt;getPubDate(&amp;#x27;U&amp;#x27;));
    $importPost-&amp;gt;save();
  }
&lt;/pre&gt;

&lt;p&gt;If you were to use this, you may need to change the stripped titles to unique Id - I changed my old CMS slightly to output slugs as unique ID's so that it would be easy for me to do redirects for my old URL structure.  I put this in the batch folder, and then ran it from the root of the project using :&lt;/p&gt;

&lt;pre&gt;
  php batch/rss_import.php
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/markng-symfony/~4/248007892" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://www.markng.co.uk/blog/2008/03/05/populating-sfsimpleblogplugin-from-rss</feedburner:origLink></entry>
<entry>
  <title>Quick, Dirty, Cheap API in symfony</title>
  <link rel="alternate" href="http://feeds.feedburner.com/~r/markng-symfony/~3/248007893/quick-dirty-cheap-api-in-symfony" />
  <updated>2008-02-28T22:13:00Z</updated>
  <author>
    <name>Mark</name>
  </author>
  <id>48</id>
  <summary type="text">In a project I'm working on at the moment, I had the need to quickly get together some JSON webservi[...]</summary>
  <content type="html">&lt;P&gt;In a project I'm working on at the moment, I had the need to quickly get together some JSON webservices.  I wanted to add these on to actions that I had already created, to output the data the page would have shown, thus making the pages that already exist an API structure.  The MVC pattern of &lt;A href="http://www.symfony-project.org/" title="symfony Web PHP Framework"&gt;symfony&lt;/A&gt; makes this somewhat easier to do.  Since I had a bunch of methods to create services for, I came up with this quick technique :&lt;/P&gt;

&lt;P&gt;I created a quick method to do this without having to create extra views for each action.  I added a method to the controller called 'returnApi', which looks like this :&lt;/P&gt;

&lt;PRE&gt;&lt;CODE&gt;
  /**
   * returnApi - take data and do magic to return data as an API
   *
   * @return string
   * @author Mark Ng
   **/
  private function returnApi($data, $apiType = &amp;#x27;json&amp;#x27;)
  {
    $this-&amp;gt;logMessage(&amp;#x27;returnApi called&amp;#x27;);
    // do some magic with the data here
    $outputData = null;
    if ($data instanceof BaseObject) 
    {
      $outputData = $data-&amp;gt;toArray();
    }
    elseif(is_array($data))
    {
      $outputData = array();
      foreach ($data as $key =&amp;gt; $object) 
      {
        if ($object instanceof BaseObject) 
        {
          $outputData[] = $object-&amp;gt;toArray();
        }
      }
    }
    elseif($data instanceof sfPropelPager)
    {
      foreach ($data-&amp;gt;getResults() as $key =&amp;gt; $object) 
      {
        if ($object instanceof BaseObject) 
        {
          $outputData[] = $object-&amp;gt;toArray();
        }
      }
    }
    else 
    {
      throw new Exception(&amp;#x27;unable to translate data to API&amp;#x27;);
    }
    
    switch ($apiType)
    {
      case &amp;#x27;json&amp;#x27;:
        // do json encoding and return here
        header(&amp;#x27;Content-Type: application/json&amp;#x27;);
        echo(json_encode($outputData));
        return(sfView::NONE);
        break;
      
      case &amp;#x27;yaml&amp;#x27;:
        // do yaml encoding and return here
        header(&amp;#x27;Content-Type: text/yaml&amp;#x27;);
        $yaml = new sfYaml();
        echo($yaml-&amp;gt;dump($outputData));
        return(sfView::NONE);
        break;
      
      default:
        // return a 404
        $this-&amp;gt;forward404();
        break;
    }
  }  
&lt;/CODE&gt;
&lt;/PRE&gt;&lt;P&gt;This will take :&lt;/P&gt;
&lt;UL&gt;
  &lt;LI&gt;Any propel model object instance&lt;/LI&gt;
  &lt;LI&gt;Any sfPropelPager instance&lt;/LI&gt;
  &lt;LI&gt;Any array of propel model objects&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;Passed from a action to create a view in various formats.  It's left as an exercise for the reader to create alternatives to json and yaml (XML, for example).  For each action you wish to enable this, add this snippet to the bottom of the action (remembering to replace the $this-&gt;data) with wherever you have placed your data for the action :&lt;/P&gt;

&lt;PRE&gt;  &lt;CODE&gt;
    if ($this-&amp;gt;hasRequestParameter(&amp;#x27;api&amp;#x27;)) 
    {
      return($this-&amp;gt;returnApi($this-&amp;gt;data, $this-&amp;gt;getRequestParameter(&amp;#x27;api&amp;#x27;)));
    }
  &lt;/CODE&gt;
&lt;/PRE&gt;&lt;P&gt;As always, this is blogged as soon as I have written the code, so if you notice any bugs, please don't hesitate to contact me so I can correct them.&lt;/P&gt;

&lt;p&gt;Once you have done this, all your actions are available as these api types by adding ?api=json or ?api=yaml to your URL strings.  You can also, of course, use routes with prettier urls to do this, too.&lt;img src="http://feeds.feedburner.com/~r/markng-symfony/~4/248007893" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://www.markng.co.uk/blog/2008/02/28/quick-dirty-cheap-api-in-symfony</feedburner:origLink></entry>
<entry>
  <title>facebook API authentication in symfony using sfGuard</title>
  <link rel="alternate" href="http://feeds.feedburner.com/~r/markng-symfony/~3/248007894/facebook-api-authentication-in-symfony-using-sfguard" />
  <updated>2007-09-28T15:18:00Z</updated>
  <author>
    <name>Mark</name>
  </author>
  <id>49</id>
  <summary type="text">Updated: The controller code that called the facebook API to insert the users first and last name wa[...]</summary>
  <content type="html">&lt;p&gt;&lt;strong&gt;Updated:&lt;/strong&gt; The controller code that called the facebook API to insert the users first and last name was not correct.  This has been updated.&lt;/p&gt;

&lt;p&gt;Leveraging facebooks API to bring you users is a useful technique.  As of this date, I haven't seen any plugins to automatically handle logging into an existing symfony application using facebook, so I did some integration work to make it possible.  I may roll this up into a plugin at a later date, but time doesn't allow for that at the moment (if you want to do it yourself, then let me know and I'll give you any help I can)&lt;/p&gt;

&lt;p&gt;Standard disclaimer applies - I've not yet significantly tested this code and it may eat your hamster.&lt;/p&gt;

&lt;h2&gt;Requirements&lt;/h2&gt;

&lt;p&gt;First, install &lt;a href="http://trac.symfony-project.com/trac/wiki/sfGuardPlugin" title="sfGuardPlugin - symfony - Trac"&gt;sfGuardPlugin&lt;/a&gt; as described in their instructions.  You'll also want to create a profile table with a couple of extra fields for facebook.  If you're using an XML schema, your table declaration should look like this :&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    &amp;lt;table name=&amp;quot;sf_guard_user_profile&amp;quot; phpName=&amp;quot;sfGuardUserProfile&amp;quot;&amp;gt;
      &amp;lt;column name=&amp;quot;id&amp;quot; type=&amp;quot;integer&amp;quot; autoIncrement=&amp;quot;true&amp;quot; primaryKey=&amp;quot;true&amp;quot; /&amp;gt;
      &amp;lt;column name=&amp;quot;user_id&amp;quot; type=&amp;quot;integer&amp;quot; required=&amp;quot;true&amp;quot; /&amp;gt;
      &amp;lt;foreign-key foreignTable=&amp;quot;sf_guard_user&amp;quot;&amp;gt;
        &amp;lt;reference local=&amp;quot;user_id&amp;quot; foreign=&amp;quot;id&amp;quot;/&amp;gt;
      &amp;lt;/foreign-key&amp;gt;
      &amp;lt;column name=&amp;quot;first_name&amp;quot; type=&amp;quot;varchar&amp;quot; size=&amp;quot;255&amp;quot; /&amp;gt;
      &amp;lt;column name=&amp;quot;last_name&amp;quot; type=&amp;quot;varchar&amp;quot; size=&amp;quot;255&amp;quot; /&amp;gt;
      &amp;lt;column name=&amp;quot;facebook_user_id&amp;quot; type=&amp;quot;integer&amp;quot; /&amp;gt;
      &amp;lt;column name=&amp;quot;facebook_key&amp;quot; type=&amp;quot;varchar&amp;quot; size=&amp;quot;255&amp;quot; /&amp;gt;
    &amp;lt;/table&amp;gt;  
  &lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;first_name and last_name are optional.  If you decide not to use these, then you'll need to remove lines later on that populate these fields from the facebook API.  You could also add other fields that are available from the facebook api &lt;a href="http://developers.facebook.com/documentation.php?method=users.getInfo"&gt;for which the field list is available here.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once sfGuard is installed and working (you should be able to log in as the admin user), you'll need to install the &lt;a href="http://developers.facebook.com/resources.php"&gt;facebook PHP API client&lt;/a&gt; and place the PHP files included inside into your projects /lib directory.  I also had to rename the facebook.php file Facebook.php otherwise symfonys classloader wouldn't recognise it.  Your mileage may vary.&lt;/p&gt;

&lt;h2&gt;Extending sfGuard to use facebook&lt;/h2&gt;
&lt;p&gt;In order to extend sfGuard in your application, you need to create a sfGuardAuth module to override settings within the original sfGuardAuth application in the plugin.  You can do this with the command line&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    symfony init-module &amp;lt;your-application-name-here&amp;gt; sfGuardAuth
  &lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;Once you've done this, remove the executeIndex method from the actions.class.php that is generated and the indexSuccess.php template.  You'll need to copy some files from the plugin directly into the same place in your new module directory :&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    plugins/sfGuardPlugin/modules/sfGuardAuth/config/security.yml
    plugins/sfGuardPlugin/modules/sfGuardAuth/templates/signinSuccess.php
  &lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;Edit security.yml to add this at the end - this allows people who are not signed in to access the facebooksignin action&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    facebooksignin:
      is_secure: off
  &lt;/pre&gt;
&lt;/code&gt;


&lt;p&gt;You will also need to add both facebook_api_key and facebook_secret keys to your settings.yml containing your api key and secret.&lt;/p&gt;

&lt;p&gt;Now add the following code into your new actions class :&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    /**
     * executeFacebooksignin - log in using a facebook account
     *
     * @return void
     * @author Mark Ng
     **/
    public function executeFacebooksignin()
    {
      // force a facebook login
      $facebook = new Facebook(sfConfig::get(&amp;#x27;sf_facebook_api_key&amp;#x27;),sfConfig::get(&amp;#x27;sf_facebook_secret&amp;#x27;));
      $fbUserId = $facebook-&amp;gt;require_login();

      $profile = sfGuardUserProfilePeer::retrieveByFacebookUserId($fbUserId);
      // check if a user profile exists with that facebook ID
      if ($profile instanceof sfGuardUserProfile)
      {
        $user = $profile-&amp;gt;getSfGuardUser();
      }
      else
      {
        // no user with that facebook account, so make one
        $user = new sfGuardUser();
        $user-&amp;gt;setUsername(&amp;#x27;facebook:&amp;#x27;.$fbUserId);
        $user-&amp;gt;save();
        $profile = $user-&amp;gt;getProfile();
        $profile-&amp;gt;setFacebookUserId($fbUserId);
      }
      // update these, as they could have changed and are not immutable
      $profile-&amp;gt;setFacebookKey($facebook-&amp;gt;api_client-&amp;gt;session_key);
      $userinfo = $facebook-&amp;gt;api_client-&amp;gt;users_getInfo($facebook-&amp;gt;user,array(&amp;#x27;first_name&amp;#x27;,&amp;#x27;last_name&amp;#x27;));
      $profile-&amp;gt;setFirstName($userinfo[0][&amp;#x27;first_name&amp;#x27;]);
      $profile-&amp;gt;setLastName($userinfo[0][&amp;#x27;last_name&amp;#x27;]);
      $user-&amp;gt;save();
      $profile-&amp;gt;save();

      // sign the user in
      $this-&amp;gt;getContext()-&amp;gt;getUser()-&amp;gt;signIn($user);

      $this-&amp;gt;redirect(&amp;#x27;/&amp;#x27;);
    }
    
  &lt;/pre&gt;
&lt;/code&gt;
&lt;p&gt;You may want to change the way that the username is assigned.  If your application allows the : character in usernames, someone could possibly cause security mischief.  You'll need to find some other way of assigning a facebook user a unique username in your system.&lt;/p&gt;
&lt;p&gt;Then add a link to your signinsuccess.php template, to show a link to this action to log in to facebook something like this :&lt;/p&gt;

&lt;code&gt;
  &lt;pre&gt;
    &amp;lt;?php echo link_to(&amp;#x27;Sign in with your facebook account&amp;#x27;, &amp;#x27;sfGuardAuth/facebooksignin&amp;#x27;) ?&amp;gt;
  &lt;/pre&gt;
&lt;/code&gt;

&lt;p&gt;And you should now be able to log in via facebook (after you've set your callback url in your facebook application).&lt;/p&gt;

&lt;p&gt;I wrote this article directly after hacking this together for an application I was working on.  If you find it doesn't work, it's likely that I've missed something.  Please contact me via the contact section of the site and I'll help you fix it (and amend this page).&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/markng-symfony/~4/248007894" height="1" width="1"/&gt;</content>
<feedburner:origLink>http://www.markng.co.uk/blog/2007/09/28/facebook-api-authentication-in-symfony-using-sfguard</feedburner:origLink></entry>
</feed>
