1<?php
2
3/**
4 * PHP5 interface for Facebook's REST API
5 *
6 * PHP version 5.1.0+
7 *
8 * LICENSE: This source file is subject to the New BSD license that is
9 * available through the world-wide-web at the following URI:
10 * http://www.opensource.org/licenses/bsd-license.php. If you did not receive
11 * a copy of the New BSD License and are unable to obtain it through the web,
12 * please send a note to license@php.net so we can mail you a copy immediately.
13 *
14 * @category  Services
15 * @package   Services_Facebook
16 * @author    Joe Stump <joe@joestump.net>
17 * @copyright 2007-2008 Joe Stump <joe@joestump.net>
18 * @license   http://www.opensource.org/licenses/bsd-license.php New BSD License
19 * @version   Release: 0.2.14
20 * @link      http://pear.php.net/package/Services_Facebook
21 */
22
23require_once 'Services/Facebook/Common.php';
24
25/**
26 * Facebook Feed Interface
27 *
28 * @category Services
29 * @package  Services_Facebook
30 * @author   Joe Stump <joe@joestump.net>
31 * @license  http://www.opensource.org/licenses/bsd-license.php New BSD License
32 * @version  Release: 0.2.14
33 * @link     http://wiki.developers.facebook.com
34 */
35class Services_Facebook_Feed extends Services_Facebook_Common
36{
37    /**
38     * Publish a story to a user's feed
39     *
40     * The $images array should be a numerically indexed array of arrays, where
41     * each image has two keys: src and href. The src is the full URI of the
42     * image and the href is the link of that image.
43     *
44     * <code>
45     * <?php
46     * $images = array(
47     *     array('src'  => 'http://example.com/images1.jpg',
48     *           'href' => 'http://example.com/images.php?image=1'),
49     *     array('src'  => 'http://example.com/images2.jpg',
50     *           'href' => 'http://example.com/images.php?image=2'),
51     *     array('src'  => 'http://example.com/images3.jpg',
52     *           'href' => 'http://example.com/images.php?image=3')
53     * );
54     * ?>
55     * </code>
56     *
57     * @param string $title  FBML to post as story title
58     * @param string $body   FBML to post as story body
59     * @param array  $images Images to post to story entry
60     *
61     * @return boolean
62     *
63     * @link http://wiki.developers.facebook.com/index.php/Feed.publishStoryToUser
64     * @link http://wiki.developers.facebook.com/index.php/PublishActionOfUser_vs._PublishStoryToUser
65     */
66    public function publishStoryToUser($title,
67                                       $body = '',
68                                       array $images = array())
69    {
70        $args = array(
71            'title' => $title,
72            'session_key' => $this->sessionKey
73        );
74
75        if (strlen($body)) {
76            $args['body'] = $body;
77        }
78
79        if (count($images)) {
80            // Facebook only allows four images so don't send more than that.
81            $cnt = count($images);
82            if ($cnt > 4) {
83                $cnt = 4;
84            }
85
86            for ($i = 0 ; $i < $cnt ; $i++) {
87                $n = ($i + 1);
88                $args['image_' . $n] = $images[$i]['src'];
89                if (isset($images[$i]['href'])) {
90                    $args['image_' . $n . '_link'] = $images[$i]['href'];
91                } else {
92                    $args['image_' . $n . '_link'] = $images[$i]['src'];
93                }
94            }
95        }
96
97        $result = $this->callMethod('feed.publishStoryToUser', $args);
98        $check  = intval((string)$result->feed_publishStoryToUser_response_elt);
99        return ($check == 1);
100    }
101
102    /**
103     * Publish an action to a user's feed
104     *
105     * An action differs from a story in that a user's action is sent to all
106     * of that user's friends as well.
107     *
108     * The $images array should be a numerically indexed array of arrays, where
109     * each image has two keys: src and href. The src is the full URI of the
110     * image and the href is the link of that image.
111     *
112     * <code>
113     * <?php
114     * $images = array(
115     *     array('src'  => 'http://example.com/images1.jpg',
116     *           'href' => 'http://example.com/images.php?image=1'),
117     *     array('src'  => 'http://example.com/images2.jpg',
118     *           'href' => 'http://example.com/images.php?image=2'),
119     *     array('src'  => 'http://example.com/images3.jpg',
120     *           'href' => 'http://example.com/images.php?image=3')
121     * );
122     * ?>
123     * </code>
124     *
125     * @param string $title  FBML to post as story title
126     * @param string $body   FBML to post as story body
127     * @param array  $images Images to post to story entry
128     *
129     * @return boolean
130     *
131     * @link http://wiki.developers.facebook.com/index.php/Feed.publishActionOfUser
132     * @link http://wiki.developers.facebook.com/index.php/PublishActionOfUser_vs._PublishStoryToUser
133     */
134    public function publishActionOfUser($title,
135                                        $body = '',
136                                        array $images = array())
137    {
138        $args = array(
139            'title' => $title,
140            'session_key' => $this->sessionKey
141        );
142
143        if (strlen($body)) {
144            $args['body'] = $body;
145        }
146
147        if (count($images)) {
148            // Facebook only allows four images so don't send more than that.
149            $cnt = count($images);
150            if ($cnt > 4) {
151                $cnt = 4;
152            }
153
154            for ($i = 0 ; $i < $cnt ; $i++) {
155                $n = ($i + 1);
156                $args['image_' . $n] = $images[$i]['src'];
157                if (isset($images[$i]['href'])) {
158                    $args['image_' . $n . '_link'] = $images[$i]['href'];
159                } else {
160                    $args['image_' . $n . '_link'] = $images[$i]['src'];
161                }
162            }
163        }
164
165        $result = $this->callMethod('feed.publishActionOfUser', $args);
166        $check  = intval((string)$result->feed_publishActionOfUser_response_elt);
167        return ($check == 1);
168    }
169
170    /**
171     * Publish a templatized action to a user's feed
172     *
173     * An action differs from a story in that a user's action is sent to all
174     * of that user's friends as well.
175     *
176     * An templatized story publishes News Feed stories to the friends of that user.
177     * These stories or more likely to appear to the friends of that user depending
178     * upon a variety of factors, such as the closeness of the relationship between
179     * the users, the interaction data facebook has about that particular story type,
180     * and the quality of the content in the story/on the linked page.
181     * http://wiki.developers.facebook.com/index.php/FeedRankingFAQ
182     *
183     * The $images array should be a numerically indexed array of arrays, where
184     * each image has two keys: src and href. The src is the full URI of the
185     * image and the href is the link of that image.
186     *
187     * <code>
188     * <?php
189     * $images = array(
190     *     array('src'  => 'http://example.com/images1.jpg',
191     *           'href' => 'http://example.com/images.php?image=1'),
192     *     array('src'  => 'http://example.com/images2.jpg',
193     *           'href' => 'http://example.com/images.php?image=2'),
194     *     array('src'  => 'http://example.com/images3.jpg',
195     *           'href' => 'http://example.com/images.php?image=3')
196     * );
197     * ?>
198     * </code>
199     *
200     * @param string $titleTemplate FBML to post as the title, must contain {actor}
201     * @param array  $feedData      Array containing optional Feed template, data, and/or actor id
202     * @param array  $images        Images to post to story entry
203     *
204     * @return boolean
205     *
206     * @author Jeff Hodsdon <jeffhodsdon@gmail.com>
207     * @link   http://wiki.developers.facebook.com/index.php/Feed.publishTemplatizedAction
208     */
209    public function publishTemplatizedAction($titleTemplate,
210                                             array $feedData = array(),
211                                             array $images = array())
212    {
213        $args = array(
214            'title_template' => $titleTemplate,
215            'session_key' => $this->sessionKey
216        );
217
218        static $options = array('title_data', 'body_template', 'body_data',
219                                'body_general', 'page_actor_id');
220
221        foreach ($options as $opt) {
222            if (isset($feedData[$opt]) && strlen($feedData[$opt])) {
223                $args[$opt] = $feedData[$opt];
224            }
225        }
226
227        if (count($images)) {
228            // Facebook only allows four images so don't send more than that.
229            $cnt = count($images);
230            if ($cnt > 4) {
231                $cnt = 4;
232            }
233
234            for ($i = 0 ; $i < $cnt ; $i++) {
235                $n = ($i + 1);
236                $args['image_' . $n] = $images[$i]['src'];
237                if (isset($images[$i]['href'])) {
238                    $args['image_' . $n . '_link'] = $images[$i]['href'];
239                } else {
240                    $args['image_' . $n . '_link'] = $images[$i]['src'];
241                }
242            }
243        }
244
245        $result = $this->callMethod('feed.publishTemplatizedAction', $args);
246        return (intval((string)$result) == 1);
247    }
248
249    /**
250     * Builds a template bundle around the specified templates, registers them
251     * on Facebook, and responds with a template bundle ID that can be used
252     * to identify your template bundle to other Feed-related API calls.
253     *
254     * A template bundle consists of:
255     *  - an array of one line story templates
256     *  - an array of short story templates
257     *  - a single full story template
258     *
259     * Each array consists of one or more templates, and each template consists
260     * of one or more tokens (for the story actor, friends, items, and so
261     * forth), some static text, and some FBML. Tokens must be wrapped in curly
262     * braces and asterisks, as in {*actor*}. The {*actor*} token must appear
263     * at the beginning of all one line templates and at the beginning of short
264     * and full template story titles.
265     *
266     * The order of templates in an array is very important. In general, the
267     * most flexible template should be first in the array. The most flexible
268     * template has the most tokens in it. The first template will always be used
269     * for feed stories. The last one-line template in the array must be the
270     * least flexible of all the template in the bundle. Thus, it should include
271     * only tokens that are a strict subset of all other tokens.
272     *
273     * When considering these templates, the first template makes for the best
274     * story, but the last template has the highest aggregation potential. When
275     * you publish a story using feed.publishUserAction, you're posting the
276     * first version of the story to a user's Mini-Feed, and you're posting one
277     * of three different stories to that users friends' News Feeds.
278     *
279     * Short story each consist of two parts, a template title and a template
280     * body. Short stories should be passed as an array of short stories,
281     * with each element being an array containing the keys 'template_title'
282     * and 'template_body'
283     *
284     * Full story templates should be passed as an array containing keys
285     * 'template_title' and 'template_body'
286     *
287     * Action links @see http://wiki.developers.facebook.com/index.php/Action_Links
288     *
289     * @access  public
290     * @param   array   $oneLineStoryTpls   array of one-line story templates
291     * @param   array   $shortStoryTpls     optional array of short story templates
292     * @param   array   $fullStoryTemplate  optional full story template
293     * @param   array   $actionLinks        optional array of actoin link records
294     * @return  string  template bundle ID of newly registered bundle
295     * @link    http://wiki.developers.facebook.com/index.php/Feed.registerTemplateBundle
296     * @author  Matthew Fonda <matthewfonda@gmail.com>
297     */
298    public function registerTemplateBundle(array $oneLineStoryTpls,
299                                           array $shortStoryTpls = array(),
300                                           array $fullStoryTpl = array(),
301                                           array $actionLinks = array())
302    {
303        $args = array();
304        if (count($oneLineStoryTpls)) {
305            $args['one_line_story_templates'] = json_encode($oneLineStoryTpls);
306        } else {
307            throw new Services_Facebook_Exception(
308                    'Feed.registerTemplateBundle requires at least one one-line story template'
309                );
310        }
311
312        if (count($shortStoryTpls)) {
313            $args['short_story_templates'] = json_encode($shortStoryTpls);
314        }
315
316        if (isset($fullStoryTpl['template_title'], $fullStoryTpl['template_body'])) {
317            $args['full_story_template'] = json_encode($fullStoryTpl);
318        }
319
320        if (count($actionLinks)) {
321            $args['action_links'] = json_encode($actionLinks);
322        }
323
324        $result = $this->callMethod('feed.registerTemplateBundle', $args);
325        return (float) (string)$result;
326    }
327
328    /**
329     * Retrieves the full list of all template bundles registered by the
330     * requesting application. This does not include any template bundles
331     * previously deactivated via calls to feed.deactivateTemplateBundle
332     *
333     * @access  public
334     * @return  SimpleXMLElement    SimpleXMLElement containing templates
335     * @link    http://wiki.developers.facebook.com/index.php/Feed.getRegisteredTemplateBundles
336     * @author  Matthew Fonda <matthewfonda@gmail.com>
337     */
338    public function getRegisteredTemplateBundles()
339    {
340        return $this->callMethod('feed.getRegisteredTemplateBundles');
341    }
342
343    /**
344     * Returns information about a specified template bundle previously
345     * registered by the requesting application. The result is returned
346     * as a SimpleXMLElement.
347     *
348     * @access  public
349     * @param   int                 $id     ID of template bundle
350     * @return  SimpleXMLElement    SimpleXMLElement representing the bundle
351     * @link    http://wiki.developers.facebook.com/index.php/Feed.getRegisteredTemplateBundleByID
352     * @author  Matthew Fonda <matthewfonda@gmail.com>
353     */
354    public function getRegisteredTemplateBundleByID($id)
355    {
356        $args = array('template_bundle_id' => $id);
357        return $this->callMethod('feed.getRegisteredTemplateBundleByID', $args);
358    }
359
360    /**
361     * Deactivates a previously registered template bundle. Once a template
362     * bundle has been deactivated, it can no longer be used to publish stories
363     * via feed.publishUserAction. Stories published agaisnt the template
364     * bundle prior to its deactivation are still valid and will show up in the
365     * Mini-Feed and News Feed. The response is true if and only if the template
366     * bundle, identified by $id, is an active template bundle owned by the
367     * requesting application, and is false otherwise.
368     *
369     * @access  public
370     * @param   int     $id     ID of template bundle to deactivate
371     * @return  boolean
372     * @link    http://wiki.developers.facebook.com/index.php/Feed.deactivateTemplateBundleByID
373     * @author  Matthew Fonda <matthewfonda@gmail.com>
374     */
375    public function deactivateTemplateBundleByID($id)
376    {
377        $args = array('template_bundle_id' => $id);
378        $result = $this->callMethod('feed.deactivateTemplateBundleByID', $args);
379        return (intval($result) == 1);
380    }
381
382    /**
383     * Publishes a story on behald of the user owning the session, using the
384     * specified template bundle. This method requires an active session key
385     * in order to be called. This method returns true if all succeeds, and
386     * false of the user never authorized the application to publish to his or
387     * her Mini-Feed.
388     *
389     * This method should be passed a template bundle ID to use, and an array
390     * of template data whose keys are the tokens to replace, and values are
391     * the desired replacement. 'actor' and 'target' are special tokens and
392     * should not be included in this array. If one or more of the templates
393     * include tokens other than 'actor' and 'targets', then this array is
394     * required. This array can also include exactly one of the following keys:
395     * 'images', 'flash', 'mp3', or 'video'.
396     *
397     * If 'images' is passed, it should map to an array of up to four images,
398     * and each array should contain a key 'src', and optionally 'href'
399     *
400     * If 'flash' is passed, it should map to an array containing two required
401     * keys: 'swfsrc', which is the URL of the flash object to be rendered, and
402     * 'imgsrc', which is the URL of an image to be displayed until the users
403     * clicks the flash object. Optionally, the 'flash' array can contain 'width'
404     * and 'height'. The height must be an integer between 30 and 100 (inclusive),
405     * and the width must be either 100, 110, or 130.
406     *
407     * If 'mp3' is passed, it must contain a single required field, 'src', and
408     * can optionally contain 'title', 'artist', and 'album'
409     *
410     * If 'video' is passed, it must contain two required fields: 'video_src'
411     * and 'preview_img'. The video array can also contain the following
412     * optional fields: 'video_title', 'video_link', and 'video_type'.
413     *
414     * If the template in questions contains a 'target' token, the userIDs
415     * of the target should be passed as an array, $targetIDs.
416     *
417     * @access  public
418     * @param   int     $templateBundleID   ID of template bundle to use
419     * @param   array   $templateData       array of template data
420     * @param   array   $targetIDs          array of target IDs
421     * @param   string  $bodyGeneral        additional markup that extends the
422     *                                      body of a short story
423     * @return  boolean
424     * @link    http://wiki.developers.facebook.com/index.php/Feed.publishUserAction
425     * @author  Matthew Fonda <matthewfonda@gmail.com>
426     */
427    public function publishUserAction($templateBundleID,
428                                      array $templateData = array(),
429                                      array $targetIDs = array(),
430                                      $bodyGeneral = ''
431                                     )
432    {
433        $args = array('session_key'        => $this->sessionKey,
434                      'template_bundle_id' => $templateBundleID
435                     );
436        if (count($templateData)) {
437            $args['template_data'] = json_encode($templateData);
438        }
439
440        if (count($targetIDs)) {
441            $args['target_ids'] = implode(',', $targetIDs);
442        }
443
444        if (strlen($bodyGeneral)) {
445            $args['body_general'] = $bodyGeneral;
446        }
447
448        $result = $this->callMethod('feed.publishUserAction', $args);
449        return (intval($result->feed_publishUserAction_response_elt) == 1);
450    }
451
452}
453
454?>
455