Your own cakephp file-browser for ckeditor: part 4 – flickr photos and slideshow

As we have seen in the previous post (Your own cakephp file-browser for ckeditor: part 3 – youtube videos), it’s not hard to implement a search/browser of external data sources, with the ability to embed the desired formatted media in ckeditor.

Here’s a similar approach, interacting with Flickr’s API, with a catch.

The ingredients are almost the same of a popular article by Johnatant Snook on Site Point.

Drop the phpFlickr class in the vendor folder (i used version 2.3.1).

Get the FlickrComponent – a bridge to the phpFlick class, that loads it as a cake component – and the chasm between cakephp and the Flikr Api is crossed.

It’s all we need to populate our popup browser, by querying flickr.

We want to look for pohots and photosets – se the user can embed a single image or a slideshow. The catch is, there is no way to directly look for photosets.

Se, we look for photos, and optionally get the photosets it belongs to, with a second ajax action.

The other thing to consider is, the component itself is heavy and adds an unnecessary overhead in other “browsers”.

So, this time we create a new controller (AssetsFlickrController) that extends owr AssetController, and it’s used only for the flickr borwser popup.

Here, we implement two actions: the main index (with search and pagination) and an ajax action to get the selected picture and her related photosets.

The first method:

  1. <?php
  2. function admin_flickrbrowser($opener_instance, $page = 1, $per_page = 10, $id = null) {
  3. $this->_clean_params();
  4. // get the query parameters
  5. if(isset($this->data['Asset'])) {
  6. if (isset($this->data['Asset']['keyword']) && $this->data['Asset']['keyword'] != '')    $keyword  = $this->data['Asset']['keyword']; else $keyword = 'volontariato';
  7. if (isset($this->data['Asset']['author']) && $this->data['Asset']['author'] != '')     $author   = $this->data['Asset']['author'];
  8. }
  9. if(isset($author) && !empty($author)) {
  10. $username = $this->flickr->people_findByUsername($author);
  11. $photosets = $this->flickr->photosets_getList($username['id']);
  12. $this->set('photosets', $photosets['photoset']);
  13. } else
  14. if(isset($keyword) && !empty($keyword)) {
  15. $thumbs  = $this->flickr->photos_search(array(
  16. 'text' => $keyword,
  17. 'page' => $page,
  18. 'per_page' => $per_page,
  19. 'sort' => 'interestingness-desc',
  20. 'extras' => 'license,date_upload,owner_name,icon_server,original_format,tags,o_dims,views,media,path_alias'
  21. ));
  22. }
  23. if(isset($thumbs)) {
  24. if($page == 1) $this->Session->write('total_pages', $thumbs['pages']);
  25. } else {
  26. $this->Session->write('total_pages', 1);
  27. }
  28. if($page < $this->Session->read('total_pages')) {
  29. $next_index = $page + 1;
  30. $url = array('controller' => 'assets', 'action' => 'flickrbrowser',
  31. $opener_instance,
  32. $next_index,
  33. $per_page
  34. );
  35. if (isset($keyword)) $url['keyword'] = $keyword;
  36. if (isset($author)) $url['author'] = $author;
  37. $this->set('next_url', $url);
  38. }
  39. if($page > 1) {
  40. $previous_index = $page - 1;
  41. $url = array('controller' => 'assets', 'action' => 'flickrbrowser',
  42. $opener_instance,
  43. $previous_index,
  44. $per_page
  45. );
  46. if (isset($keyword)) $url['keyword'] = $keyword;
  47. if (isset($author)) $url['author'] = $author;
  48. $this->set('previous_url', $url);
  49. }
  50. if(isset($thumbs)) $this->set('thumbs', $thumbs);
  51. $this->set('opener_instance', $opener_instance);
  52. $this->render('admin_flickrbrowser', 'basic');
  53. }
  54. }
  55. ?>

As you see, the action gets the search parameters (form the popup’s form), and then performs the search -by author or keyword.

If the search was by username, we ask Flickr for author details, and then get his photosets with another query to flicker, using the user id found in the previous query:

$username = $this->flickr->people_findByUsername($author);
$photosets = $this->flickr->photosets_getList($username['id']);

If the search is by keywords, we ask flicker for related pictures (by name, tag..) and get some extra info on the picture. (see Flicker API for more details)

$thumbs  = $this->flickr->photos_search(array(
		    'text' => $keyword,
		    'page' => $page,
		    'per_page' => $per_page,
		    'sort' => 'interestingness-desc',
		    'extras' => 'license,date_upload,owner_name,icon_server,original_format,tags,o_dims,views,media,path_alias'
		));

Then we set the variables for the view and handle “pagination” (using the flickr->photo_search provided parameters, page and per_page).

In the (popup) view, we list the paginated pictures found (or user’s photosets).

We use the phpFlickr methods to show thumbnails and build the photo url:

  1. <?php
  2. echo $javascript->link('prototype', false);
  3. echo $javascript->link('src/scriptaculous.js?load=effects,controls', false);
  4. ?>
  5. <script type="text/javascript">
  6. <!--
  7. function InsertHTML(passed)
  8. {
  9.     var oEditor = opener.CKEDITOR.instances.<?php echo $opener_instance ?>;
  10.     // Check the active editing mode.
  11.     if ( oEditor.mode == 'wysiwyg' )
  12.     {
  13.         // Insert the desired HTML.
  14.         oEditor.insertHtml( passed ) ;
  15.     }
  16.     else
  17.         alert('<?php echo __('You must be on WYSIWYG mode!', true); ?>') ;
  18. window.close();
  19. }
  20. function hide(id) {
  21. document.getElementById(id).style.display = 'none';
  22. }
  23. -->
  24. </script>
  25. <div class="pannello">
  26. <h2><?php __('Photos and slideshow from Flickr');?></h2>
  27. <div class="art-Block">
  28. <p>
  29. <?php
  30. echo __('Search Flickr Photos or photosets by user');
  31. ?>
  32. </p>
  33. <?php echo $form->create('Asset',
  34. array('url'=>array('controller' => 'assets_flickr', 'action'=>'flickrbrowser', $opener_instance)
  35. , 'type' => 'post'));?>
  36. <table border="0" cellpadding="10">
  37. <tbody>
  38. <tr>
  39. <td>
  40. <?php  echo $html->image('social_me/big/flickr.png', array('align' => 'absmiddle', 'hspace' => '2'));; ?>
  41. </td>
  42. <td valign="middle">
  43. <?php
  44. echo $form->input('keyword', array('class' => 'size120', 'label' => __('Keywords', true)));
  45. ?>
  46. </td>
  47. <td valign="middle">
  48. <?php  __('OR'); ?>
  49. </td>
  50. <td valign="middle">
  51. <?php
  52. echo $form->input('author', array('class' => 'size120', 'label' => __('Author / User Name',true) ));
  53. ?>
  54. </td>
  55. </tr>
  56. </tbody>
  57. </table>
  58. <?php
  59. echo '<br>'. $form->submit(__('Search',true), array('div' => false, 'class' => 'art-button')); ?>
  60. <?php echo $form->end(); ?>
  61. </div>
  62. <div style="clear:both"></div>
  63. <?php $i=0; ?>
  64. <?php if (isset($thumbs)) : ?>
  65. <h2><?php
  66. if(isset($previous_url)) echo $html->link('<<', $previous_url). ' | ';
  67. if(isset($next_url)) echo $html->link('>>', $next_url); ?>
  68. </h2>
  69. <table cellpadding="0" cellspacing="0">
  70. <?php
  71. foreach($thumbs['photo'] as $item): ?>
  72. <?php
  73. $item['title'] = htmlentities($item['title'], ENT_QUOTES);
  74. $item['ownername'] = htmlentities($item['ownername'], ENT_QUOTES);
  75. $item['tags'] = htmlentities($item['tags'], ENT_QUOTES);
  76. $item['ownername'] = htmlentities($item['ownername'], ENT_QUOTES);
  77. ?>
  78. <tr>
  79. <td>
  80. <?php
  81. //
  82. // AJAX ACTION
  83. //
  84. echo $ajax->link(
  85. $html->image($flickr->buildPhotoURL($item, "small")),
  86. null,
  87. array('escape' => false,
  88. 'update' => 'show_actions_'. ++$i,
  89. 'url'=> array('action' => 'flickrGetDetails', $item['id'], ),
  90. 'indicator' => 'loading_'.$i
  91. ),
  92. null,
  93. false); ?>
  94. </td>
  95. <td>
  96. <h4><?php echo $item['title']?></h4>
  97. <div><strong><?php echo __('tags: ', true)?></strong> <?php echo  $item['tags']; ?></div>
  98. <div><strong><?php echo __('views: ', true)?></strong> <?php echo $item['views']; ?></div>
  99. <div><strong><?php echo __('owner name: ', true)?></strong> <?php echo $item['ownername'];
  100. ?></div>
  101. <div id="loading_<?php echo $i; ?>" class="loading" style="display: none;">><?php echo $html->image('loading.gif'); ?></div>
  102. <div id="show_actions_<?php echo $i; ?>">
  103. </div>
  104. </td>
  105. </tr>
  106. <?php endforeach; ?>
  107. </table>
  108. <h2><?php
  109. if(isset($previous_url)) echo $html->link('<<', $previous_url). ' | ';
  110. if(isset($next_url)) echo $html->link('>>', $next_url); ?>
  111. </h2>
  112. <?php endif;
  113. ?>
  114. <?php if(isset($photosets)) :  ?>
  115. <table cellpadding="0" cellspacing="0">
  116. <?php
  117. foreach($photosets as $item): ?>
  118. <?php
  119. $item['title'] = htmlentities($item['title'], ENT_QUOTES);
  120. $item['ownername'] = htmlentities($item['ownername'], ENT_QUOTES);
  121. $item['tags'] = htmlentities($item['tags'], ENT_QUOTES);
  122. $item['ownername'] = htmlentities($item['ownername'], ENT_QUOTES);
  123. $item['description'] = htmlentities($item['description'], ENT_QUOTES);
  124. ?>
  125. <tr>
  126. <td>
  127. <?php
  128. $main_image = $flickr->photos_getInfo($item['primary']);
  129. ?>
  130. <?php echo $ajax->link(
  131. $html->image($flickr->buildPhotoURL($main_image, "small")),
  132. null,
  133. 'escape' => false,
  134. 'update' => 'show_actions_'. ++$i,
  135. 'url'=> array('action' => 'flickrGetDetails', $item['primary'], $item['title']),
  136. 'indicator' => 'loading_'.$i
  137. ),
  138. null,
  139. false); ?>
  140. </td>
  141. <td>
  142. <h4><?php echo $item['title']?></h4>
  143. <div><strong><?php echo __('description: ', true)?></strong> <?php echo  $item['description']; ?></div>
  144. <div><strong><?php echo $item['photos']; ?> </strong><?php echo __('photos', true)?> </div>
  145. <div><strong><?php echo $item['videos'];?> </strong><?php echo __('video', true)?></div>
  146. <div id="loading_<?php echo $i; ?>" class="loading" style="display: none;">><?php echo $html->image('loading.gif'); ?></div>
  147. <div id="show_actions_<?php echo $i; ?>">
  148. </div>
  149. </td>
  150. </tr>
  151. <?php endforeach; ?>
  152. </table>
  153. <?php endif; ?>
  154. </div>

If  an user / author is searched, the html to embed  the listed photosets is generated, like it was for the single pictures (see a previous post)

If the user is looking for photos by keyword, a link to the ajax admin_flickrGetDetails action is rendered.

Here is the full controller:

  1. <?php
  2. App::import('Sanitize');
  3. App::import('Controller', 'Assets');
  4. class AssetsFlickrController extends AssetsController {
  5. var $name = 'Assets';
  6. var $helpers = array("Html", "Form", "Javascript", "Ajax", "Time", "Text",
  7. "Utility", "Media.Medium", "Number"); //"ExtendedForm"
  8. var $components = array('Auth', 'Cookie', 'Toggle', 'Session', 'RequestHandler','Flickr');
  9. function admin_flickrbrowser($opener_instance, $page = 1, $per_page = 10, $id = null) {
  10. $this->_clean_params();
  11. // get the query parameters
  12. if(isset($this->data['Asset'])) {
  13. if (isset($this->data['Asset']['keyword']) && $this->data['Asset']['keyword'] != '')    $keyword  = $this->data['Asset']['keyword']; else $keyword = 'volontariato';
  14. if (isset($this->data['Asset']['author']) && $this->data['Asset']['author'] != '')     $author   = $this->data['Asset']['author'];
  15. }
  16. if(isset($author) && !empty($author)) {
  17. $username = $this->flickr->people_findByUsername($author);
  18. $photosets = $this->flickr->photosets_getList($username['id']);
  19. $this->set('photosets', $photosets['photoset']);
  20. } else
  21. if(isset($keyword) && !empty($keyword)) {
  22. $thumbs  = $this->flickr->photos_search(array(
  23. 'text' => $keyword,
  24. 'page' => $page,
  25. 'per_page' => $per_page,
  26. 'sort' => 'interestingness-desc',
  27. 'extras' => 'license,date_upload,owner_name,icon_server,original_format,tags,o_dims,views,media,path_alias'
  28. ));
  29. }
  30. if(isset($thumbs)) {
  31. if($page == 1) $this->Session->write('total_pages', $thumbs['pages']);
  32. } else {
  33. $this->Session->write('total_pages', 1);
  34. }
  35. if($page < $this->Session->read('total_pages')) {
  36. $next_index = $page + 1;
  37. $url = array('controller' => 'assets', 'action' => 'flickrbrowser',
  38. $opener_instance,
  39. $next_index,
  40. $per_page
  41. );
  42. if (isset($keyword)) $url['keyword'] = $keyword;
  43. if (isset($author)) $url['author'] = $author;
  44. $this->set('next_url', $url);
  45. }
  46. if($page > 1) {
  47. $previous_index = $page - 1;
  48. $url = array('controller' => 'assets', 'action' => 'flickrbrowser',
  49. $opener_instance,
  50. $previous_index,
  51. $per_page
  52. );
  53. if (isset($keyword)) $url['keyword'] = $keyword;
  54. if (isset($author)) $url['author'] = $author;
  55. $this->set('previous_url', $url);
  56. }
  57. if(isset($thumbs)) $this->set('thumbs', $thumbs);
  58. $this->set('opener_instance', $opener_instance);
  59. $this->render('admin_flickrbrowser', 'basic');
  60. }
  61. function admin_flickrGetDetails($photo_id, $title = 'photo from flickr') {
  62. $i = 0;
  63. $this->autoRender = false;
  64. $this->layout = 'ajax';
  65. $photo = $this->flickr->photos_getInfo($photo_id);
  66. $this->set('photo',  $photo);
  67. $this->set('description', $title);
  68. $context = $this->flickr->photos_getAllContexts($photo_id);
  69. $this->set('context', $context);
  70. if(isset($context['set'])&& is_array($context['set'])) {
  71. foreach($context['set'] as $photoset) {
  72. $set[] = $this->flickr->photosets_getInfo($photoset['id']);
  73. $main = $this->flickr->photos_getInfo($set[$i]['primary']);
  74. $set[$i]['primary'] = $main;
  75. $i++;
  76. }
  77. $this->set('set', $set);
  78. }
  79. $this->render('photo_context');
  80. }
  81. }
  82. ?>

So, with admin_flickrGetDetails we get the infos about the pictures, and related photosets – so we can indirectly look for photosets.

Last, here is the elemenet rendered by this action.

  1. <div style="display:block;" id="popupdiv">
  2. <div style="clear:both; padding:20px; background-color:white; border-style:solid; border-color:silver">
  3. <a href="javascript:hide('popupdiv')">
  4. <?php echo $html->image('icons/delete.png', array('align' => 'right', 'alt' => __('close',true), 'title' => __('close',true) )); ?>
  5. </a>
  6. <h4><?php __('Embed this image only'); ?></h4>
  7. <?php
  8. $photo['title'] = htmlentities($photo['title'], ENT_QUOTES);
  9. $photo['description'] = htmlentities($photo['description'], ENT_QUOTES);
  10. // generated HTML to be embedded in CKeditor
  11. $insert_left =
  12. $html->div('imageleft',
  13. "<p>".
  14. $html->link(
  15. $html->image($flickr->buildPhotoURL($photo, "small"),
  16. array('align' => 'baseline',
  17. 'alt' => $photo['title'],
  18. 'title' => $photo['title'],
  19. )
  20. ),
  21. $photo['urls']['url'][0]['_content'],
  22. //$flickr->buildPhotoURL($photo, "original"),
  23. array( 'escape' => false, 'target' => '_blank'),null,false
  24. )
  25. . "</p><p><em>".$photo['title']."</em></p>",null,false). '  &nbsp;'
  26. ;
  27. $insert_right =
  28. $html->div('imageright',
  29. "<p>".
  30. $html->link(
  31. $html->image($flickr->buildPhotoURL($photo, "small"),
  32. array('align' => 'baseline',
  33. 'alt' => $photo['title'],
  34. 'title' => $photo['title'],
  35. )
  36. ),
  37. $photo['urls']['url'][0]['_content'],//$flickr->buildPhotoURL($photo, "original"),
  38. array('escape' => false, 'target' => '_blank'),null,false
  39. )."</p><p><em>".$photo['title']."</em></p>",null,false). '  &nbsp;'
  40. ;
  41. $insert_center =
  42. $html->div('imagecenter',
  43. "<p>".
  44. $html->link(
  45. $html->image($flickr->buildPhotoURL($photo, "medium"),
  46. array('align' => 'baseline',
  47. 'alt' => $photo['title'],
  48. 'title' => $photo['title'],
  49. )
  50. ),
  51. $photo['urls']['url'][0]['_content'],//$flickr->buildPhotoURL($photo, "original"),
  52. array('escape' => false, 'target' => '_blank'),null,false
  53. )."</p><p><em>".$photo['title']."</em></p>",null,false). ' &nbsp;'
  54. ;
  55. echo $html->link($html->image('icons_big/Image_Left.png',
  56. array('alt' => __('embed image', true), 'title' => __('embed image, align left', true), 'border' => 0, 'align' => 'absmiddle')),
  57. 'javascript:InsertHTML(\''. $insert_left .'\');',
  58. 'escape' => false,
  59. ),
  60. null, false
  61. );
  62. echo ' ';
  63. echo $html->link($html->image('icons_big/Image_Center.png',
  64. array('alt' => __('embed image', true), 'title' => __('embed image, big, center', true), 'border' => 0, 'align' => 'absmiddle')),
  65. 'javascript:InsertHTML(\''. $insert_center .'\');',
  66. array('escape' => false,
  67. ),
  68. null, false
  69. );
  70. echo ' ';
  71. echo $html->link($html->image('icons_big/Image_Right.png',
  72. array('alt' => __('embed image',true), 'title' => __('embed image, align right', true), 'border' => 0, 'align' => 'absmiddle')),
  73. 'javascript:InsertHTML(\''. $insert_right .'\');',
  74. array('escape' => false,
  75. ),
  76. null, false
  77. );
  78. ?>
  79. </div>
  80. <?php if(isset($set)): ?>
  81. <div style="clear:both; padding:20px; background-color:white; border-style:solid; border-color:silver">
  82. <h4><?php __('Or Embed Photosets'); ?></h4>
  83. <?php foreach($set as $thisset): ?>
  84. <?php
  85. $thisset['title'] = htmlentities($thisset['title'], ENT_QUOTES);
  86. $thisset['description'] = htmlentities($thisset['description'], ENT_QUOTES);
  87. ?>
  88. <div style="clear:both; padding:10px;  border-style:dotted; border-color:silver">
  89. <h5><?php
  90. echo $html->image($flickr->buildPhotoURL($thisset['primary'], "thumbnail")
  91. , array('align' => 'left', 'hspace' => 3, 'vspace' => 3));
  92. ?>
  93. <?php echo $thisset['title']; ?></h5>
  94. <p>
  95. <?php  echo $thisset['description']; ?>
  96. </p>
  97. <div style="clear:both">
  98. <?php
  99. $slideshow = '<object width="700" height="525"> <param name="flashvars" value="offsite=true&lang=it-it&page_show_url=%2Fphotos%2F'.$thisset['owner'].'%2Fsets%2F'.$thisset['id'].'%2Fshow%2F&page_show_back_url=%2Fphotos%2F'.$thisset['owner'].'%2Fsets%2F'.$thisset['id'].'%2F&set_id='.$thisset['id'].'&jump_to="></param> <param name="movie" value="http://www.flickr.com/apps/slideshow/show.swf?v=71649"></param> <param name="allowFullScreen" value="true"></param><embed type="application/x-shockwave-flash" src="http://www.flickr.com/apps/slideshow/show.swf?v=71649" allowFullScreen="true" flashvars="offsite=true&lang=it-it&page_show_url=%2Fphotos%2F'.$thisset['owner'].'%2Fsets%2F'.$thisset['id'].'%2Fshow%2F&page_show_back_url=%2Fphotos%2F'.$thisset['owner'].'%2Fsets%2F'.$thisset['id'].'%2F&set_id='.$thisset['id'].'&jump_to=" width="700" height="525"></embed></object>';
  100. echo $html->link($html->image('social_me/medium/flickr.png',
  101. array('alt' => __('embed slideshow',true), 'title' => __('embed slideshow of this photoset', true), 'border' => 0, 'align' => 'absmiddle'))
  102. . ' ' . __('embed slideshow of this photoset', true),
  103. "javascript:InsertHTML('". $slideshow ."');",
  104. array('escape' => false,
  105. ),
  106. null, false
  107. );
  108. ?>
  109. </div>
  110. </div>
  111. <?php endforeach; ?>
  112. </div>
  113. <?php endif; ?>
  114. <?php if(!isset($set)) : ?>
  115. <p><?php echo __('Sorry..'); ?></p>
  116. <h4><?php echo __('This picture is not included in any photoset'); ?></h4>
  117. <?php endif; ?>
  118. </div>

It generates the needed html and shows the options to embed it in owr  ckeditor instance (that called the popup) the single picture – like we  did for owr uploaded images, big centered or medium right or left, with  links to the original picture. This time, on Flickr.

Or, if  available, a list of photosets containing the selected pictures, and the  options to embed the needed html to show a slideshow of the photoset

Here we are. This is the end of this 4 part serie.

It was not the simplest thing in the world, but -using cakephp- was easy, wasn’t it?