# sfOpenSocialPlugin ## Overview sfOpenSocialPlugin enables you to create a full-feature OpenSocial Application using Symfony framework. This plugin gives you a complete PHP5 OO implementation of OpenSocial JavaScript API( including Gadgets core and feature-specific Gadgets), which makes you're applications robust, scalable and immune to future OpenSocial versions. This plugin is very flexible taking advantage of both PHP5 ( all the marvelous of object-oriented programming) and the MVC provided by the Symfony framework. Some of the features provided by this plugin are: * Accessing to People and relationships, Persistence and Activities. * Setup application using the "app.yml" * Making transparent DataRequests to container withing the actions and accessing to container's response inside the view. * Accessing to containers environment variables both from the action and view. * Create/access activities and Activities stream from container. * The ability to send Messages(Email/Notifications/PrivateMessages/PublicMessages) to the Owner, Viewer or Friends in the container. * Taking advantages of the Persistence available the OpenSocial containers. * Having feature specific gadgets automatically imported to your application only when used in the application. ### Implementation rules At start it's important to understand that an OpenSocial application extends the Gadget specification, that specifically corresponds to one static XML file that's imported to some container. This plugin uses one Action (that's the entry point to the application) and in "indexSucces" we import the components as we need them. ### Code tree The sfOpenSocialPlugin implements the OpenSocial API and it has more than 70 classes, so it's important to know how the plugin is structured. * **sfOpenSocialPlugin** * **lib** - This is where the OpenSocial API is implemented. * **gadgets** - This is where it's implemented Gadgets classes. * **helpers** - This is where OpenSocial helpers are implemented. * **opensocial** - This is where OpenSocial API is implemented. * **misc** * **app** * **config** - Here is the place for application config files. * **templates** - You can find here OpenSocial templates. * **module** * **config** - Configuration files to be used in OpenSocial modules * **modules** - sample models are in here * **application** - This is a sample application ## Installation * (1) Create a symfony project * (2) Create an application and initiate a module(<my_opensocial_application_module>) for you're OpenSocial application: $ symfony init-project <my_project_name> $ symfony init-app <my_opensocial_application> $ symfony init-module <my_opensocial_application> <my_opensocial_application_module> * (3) Install the sfOpenSocialPlugin * (4) Then you need to copy the file "<your_symfony_project_path>/plugins/sfOpenSocialPlugin/misc/app/templates/gadget_layout.php" to your "<my_opensocial_application>/templates" directory. The "gadget_layout.php" is going to be your default layout for your OpenSocial application. * (5) Copy the file "<your_symfony_project_path>/plugins/sfOpenSocialPlugin/misc/module/config/view.yml" to your "<my_opensocial_application_module>/config/" directory. Doing this, you're setting your "<my_opensocial_application_module>" to be rendered as an gadget. * (6) Copy the file "<your_symfony_project_path>/plugins/sfOpenSocialPlugin/misc/app/config/filters.yml" to your "<my_opensocial_application_module>/config/". You need to do this to enable "oSFilter" that is responsible to import module preferences to the gadget. * (7) The last required thing to do is to copy the file "<your_symfony_project_path>/plugins/sfOpenSocialPlugin/misc/app/config/app.yml" to your "<my_opensocial_application_module>/config/". * (8) (optional) If you want to install the sample oppensocial application( that it's included as a module called 'application') you should go to "<my_opensocial_application>/config/app.yml" and copy/paste this content: all: .settings: enabled_modules: [application](default,) ## Usage **Note:** This tutorial assumes that you have create an application called "opensocial" and an application module called "application". The first part to create an OpenSocial application is to configure it. Because an OpenSocial application is a gadget you need to say to symfony that it should render the "indexSuccess.php" as a gadget. In this plugin you can find an gadget-layout under "sfOpenSocialPlugin/misc/app/templates/" and you need to set the "indexSuccess.php" layout as a gadget-layout. This is done by setting your "apps/opensocial/modules/application/config/view.yml" like this: indexSuccess: http_metas: content-type: application/xml layout: gadget_layout After you had configured the gadget you need to configure the OpenSocial application and in this plugin you can choose two ways of doing it: * You can configure it, using the file "app.yml"; * Or using the ModulePrefs class to configure it in the Action. Configuring the application means to set key-values pairs like: * title : Optional string that provides the title of the gadget * description : Optional string that describes the gadget. * etc... Most of this values are optional but some containers use them. For more information about those values look at [Gadget Preferences](http://code.google.com/apis/gadgets/docs/reference.html#Moduleprefs_Ref). Here it's an example of how an "app.yml" file should be configured: # default values all: opensocial: base_url: api_version: 0.7 module_prefs: #ref: http://code.google.com/apis/gadgets/docs/reference.html#Moduleprefs_Ref title: My First OpenSocial Application # directory_title # title_url description: This application was created by sfOpenSocialPlugin author: Daniel Botelho author_email: botelho.daniel@gmail.com # author_affiliation # author_location # screenshot thumbnail: http://palcoprincipal.clix.pt/images/logos/logo_palco_3.jpg # height # width # scaling # scrolling # singleton # author_photo # author_aboutme # author_link # author_quote locale: * lang: en country: us # messages # language_direction requires: * feature: opensocial-0.7 # - feature: dynamic-height # - feature: setprefs # - feature: settitle # - feature: tabs # - feature: drag # - feature: grid # - feature: minimessage # - feature: analytics # - feature: flash # - feature: finance user_prefs: # ref: http://code.google.com/apis/gadgets/docs/reference.html#Userprefs_Ref # - name: difficulty # the name of the User Preference # display_name: asd # urlparam: asd # datatype: asd # required: asd # default_value: asd # enum_value: # - {value: enum1, display_value: xx } # - {value: enum2, display_value: xx} content: # ref: http://code.google.com/apis/gadgets/docs/reference.html#Content_Ref type: html # href # cdata Now that you have configured the application you can start coding it! You can find several examples under the directory our module "application" and you can test them. Also the API is well documented(in progress;) ). Here I'm going to give some simple examples and try to show all the advantages of using this plugin. ### How to use PeopleRequest to get Viewer Friends ? As you've seen it's straight forward to configure the OpenSocial application using the "app.yml", but here I'm going to use the class ModulePrefs to do this. Since we are going to configure the application from the code we should start by doing that. So in the "executeIndex" function in the "/apps/opensocial/modules/application/actions/actions.class.php" you should do this: public function executeIndex() { ModulePrefs::setTitle('My First OpenSocial Application'); ModulePrefs::setDescription('This application was created by sfOpenSocialPlugin'); ModulePrefs::setAuthor('Daniel Botelho'); ModulePrefs::setAuthorEmail('botelho.daniel@gmail.com'); ModulePrefs::setThumbnail('http://palcoprincipal.clix.pt/images/logos/logo_palco_3.jpg'); } By doing this you'll be setting the Title, Description, Author, Author Email and Thumbnail of the application. After doing this, go to the file "apps/opensocial/modules/application/templates/indexSuccess.php" and this should be it's content: <?php include_component('application','dataRequest') ?> Here we are saying that the indexSuccess is going to include the Component "dataRequest" that is located in the "application"( to understand how Components work you should look at Chapter 7 from "The Definite Guide to symfony"). Now we should go to the "/apps/opensocial/modules/application/actions/components.class.php" and configure this component like this: public function executeDataRequest() { $this->viewer_friends = new OSViewerFriends('viewer_friends'); $this->people_request = new OSPeopleRequest($this->viewer_friends); $this->people_request->addProfileDetails(OSPersonField::PROFILE_URL); $data_request = new OSDataRequest('requestInfo'); $data_request->addRequest($this->people_request); $this->data_response = $data_request->send(true); echo JSFunction::addJSTags(GadgetsUtil::registerOnLoadHandler($data_request->getDataRequestFunction())); } Then go to "apps/opensocial/modules/application/templates/_dataRequest" <div id="viewer_friends"> </div> <script type="text/javascript"> function <? echo $data_response->getJSFunction()->getName() ?>(<? echo $data_response->getJSFunction()->getArgs() ?>) { var html = *; <?php echo $data_response->getData($people_request); ?> <?php $person = new OSFriend('person'); ?> <?php echo $viewer_friends->getVarName() ?>.each(function(<?php echo $person->getVarName() ?>) { var thumb = <?php echo $person->getField(OSPersonField::THUMBNAIL_URL); ?> var profile = <?php echo $person->getField(OSPersonField::PROFILE_URL); ?> html += '<a href="' + profile + '" target="_top" style="float:left">' +'<img src="' + thumb + '"/></a>'; document.getElementById('viewer_friends').innerHTML = html; }); } </script> After doing this, go to "http://<your_symfony_url>/index.php/application" and this code should be generated: <?xml version="1.0" encoding="utf-8" ?><Module> <ModulePrefs title="My First OpenSocial Application" description="This application was created by sfOpenSocialPlugin" author="Daniel Botelho" author_email="botelho.daniel@gmail.com" thumbnail="http://palcoprincipal.clix.pt/images/logos/logo_palco_3.jpg" icon="http://palcoprincipal.clix.pt/favicon.ico"><Local lang="en" country="us" /><Require feature="opensocial-0.7" /></ModulePrefs> <Content type="html"><![CDATA[ <script type="text/javascript">function requestInfo_request() { var requestInfo = opensocial.newDataRequest(); var viewer_friends_profileDetailsRequestParams = new Array(); viewer_friends_profileDetailsRequestParams.push(opensocial.Person.Field.PROFILE_URL); var viewer_friends_peopleRequestParams = { }; viewer_friends_peopleRequestParams[opensocial.DataRequest.PeopleRequestFields.PROFILE_DETAILS] = viewer_friends_profileDetailsRequestParams; requestInfo.add(requestInfo.newFetchPeopleRequest(opensocial.DataRequest.Group.VIEWER_FRIENDS),"viewer_friends"); requestInfo.send(requestInfo_response); } </script><script type="text/javascript">gadgets.util.registerOnLoadHandler(requestInfo_request); </script><div id="viewer_friends"> </div> <script type="text/javascript"> function requestInfo_response(data) { var html = *; var viewer_friends = data.get("viewer_friends").getData(); viewer_friends.each(function(person) { var thumb = person.getField(opensocial.Person.Field.THUMBNAIL_URL); var profile = person.getField(opensocial.Person.Field.PROFILE_URL); html += '<a href="' + profile + '" target="_top" style="float:left">' +'<img src="' + thumb + '"/></a>'; document.getElementById('viewer_friends').innerHTML = html; }); } </script> ]></Content> </Module> If everything went fine, now you can go to any website that supports OpenSocial applications and install this application there to see your friends in that container. ### How to use PersonRequest to get the Viewer and Owner ? In the other example we have covered the application setup so this will not be covered again in this part. So first we need to go to "apps/opensocial/modules/application/templates/indexSuccess.php" and set the Component that is going to handle this request: <?php include_component('application','personRequest') ?> Next thing is to configure the component action in the "/apps/opensocial/modules/application/actions/components.class.php": public function executePersonRequest() { $this->viewer = new OSViewer('viewer'); $this->owner = new OSOwner('owner'); $this->viewer_request = new OSPersonRequest($this->viewer); $this->viewer_request->addProfileDetails(OSPersonField::PROFILE_URL); $this->owner_request = new OSPersonRequest($this->owner); $this->owner_request->addProfileDetails(OSPersonField::PROFILE_URL); $data_request = new OSDataRequest('requestPerson'); $data_request->addRequest($this->viewer_request); $data_request->addRequest($this->owner_request); $this->data_response = $data_request->send(true); echo JSFunction::addJSTags(GadgetsUtil::registerOnLoadHandler($data_request->getDataRequestFunction())); } Now lets take some time to understand this code. Here we have created to variables: ... $this->viewer = new OSViewer('viewer'); $this->owner = new OSOwner('owner'); ... This variables are going to be used in the "view". Next we've created to OSPersonRequest objects, one for the "viewer" and other for the "owner": ... $this->viewer_request = new OSPersonRequest($this->viewer); ... $this->owner_request = new OSPersonRequest($this->owner); ... After doing this we have to create an instance of the OSDataRequest and add to it those two request's that we want to make to the container: ... $data_request = new OSDataRequest('requestPerson'); $data_request->addRequest($this->viewer_request); $data_request->addRequest($this->owner_request); ... Now that we have the OSDataRequest created we need to send it to the container like this: ... $this->data_response = $data_request->send(true); echo JSFunction::addJSTags(GadgetsUtil::registerOnLoadHandler($data_request->getDataRequestFunction())); The last line just says to the container that the OSDataRequest created is going to be executed when the appliction is loaded. Now we are going to see the "view" that is located at "apps/opensocial/modules/application/templates/_personRequest": <div id="viewer"></div> <div id="owner"></div> <script type="text/javascript"> function <? echo $data_response->getJSFunction()->getName() ?>(<? echo $data_response->getJSFunction()->getArgs() ?>) { var html = ''; <?php echo $data_response->getData($owner_request); ?> var owner_name = <?php echo $owner->getName(); ?> var owner_thumb = <?php echo $owner->getField(OSPersonField::THUMBNAIL_URL); ?> var owner_profile = <?php echo $owner->getField(OSPersonField::PROFILE_URL); ?> var owner_nick = <?php echo $owner->getField(OSPersonField::NICKNAME); ?> html = '<a href="' + owner_profile + '" target="_top" style="float:left">' +'<img src="' + owner_thumb + '"/></a>' + owner_name + ' - '+owner_nick+'</a>'; document.getElementById("owner").innerHTML = html; <?php echo $data_response->getData($viewer_request); ?> var viewer_name = <?php echo $viewer->getName(); ?> var viewer_thumb = <?php echo $viewer->getField(OSPersonField::THUMBNAIL_URL); ?> var viewer_profile = <?php echo $viewer->getField(OSPersonField::PROFILE_URL); ?> var viewer_nick = <?php echo $viewer->getField(OSPersonField::NICKNAME); ?> html = '<a href="' + viewer_profile + '" target="_top" style="float:left">' +'<img src="' + viewer_thumb + '"/></a>' + viewer_name + ' - '+viewer_nick+'</a>'; document.getElementById("viewer").innerHTML = html <?php echo GadgetsWindow::adjustHeight(); ?> } </script> Let's look at this line: function <? echo $data_response->getJSFunction()->getName() ?>(<? echo $data_response->getJSFunction()->getArgs() ?>) Here we use the $data_response object that was generated when we've sent the OSDataRequest to the container. The $data_response is an instance of the OSDataResponse class, and this class can be handled as an JSFunction. This means that we could setup the OSDataResponse all in the Action and didn't need to even use it in the "view", but using it in the "view" gives more flexibility. Another important part in this example is the: <?php echo $data_response->getData($owner_request); ?> For us to be able to use the "$owner" or "$viewer" object, first we need to fetch that Data from the response. After doing this we can use access directly to the objects that we've created in the Action. The last thing form this example is this line: <?php echo GadgetsWindow::adjustHeight(); ?> Here we are calling one function that is from the class [gadgets.window] that's in the [http://code.google.com/apis/gadgets/docs/reference.html#Feature_Libs Feature-Specific JavaScript Libraries](http://code.google.com/apis/opensocial/docs/0.7/reference/gadgets.window.html). Calling that function generates this javascript code: gadgets.window.adjustHeight(); and there's nothing restricting you to choose to write that code instead of calling or specific static function from "GadgetsWindow::adjustHeight()". The main difference between using our object or just writing the code your self is that, if you write that code you would need to manually import "<Require feature="dynamic-height" /> " to you're gadget( either, by setting in the "app.yml" or by calling the function OSConfig::importFeatureDynamicHeight()), and if you use "GadgetsWindow" instead you don't need to worry about that because it will be imported automatically for you. ### How to create an Activity ? Using activities are very simple and to create an OSActivity in the Action is as simple as: public function executeActivity(){ $this->activity = new OSActivity('update_musics'); $this->mediaItem = new OSActivityMediaItem('logo'); $this->mediaItem->setImageItem(); $this->mediaItem->setURL('http://palcoprincipal.clix.pt/images/logos/logo_palco_01.jpg'); $this->activity->addMediaItem($this->mediaItem); $this->activity->setTitle('New Music Added!'); $this->activity->createActivity(true); }