![]() |
|
Snippets |
|
In here I will be using sfWidgetFormJQueryAutocompleterMany ( http://forum.symfony-project.org/index.php/m/77584/#msg_77462 ) to ease the relating of an object to other objects (hence keywords/tags/recepients... management becomes heaven based on non religious views).
The ORM used is Doctrine.
For this to make any sense I will tie the snippet to a quick tutorial like explanation. In the blog tutorials spirit I will now implement the widget into blog post tags management.
Currently you can download it from the forum thread linked above. If let it will become part of sfFormExtraPlugin ( http://www.symfony-project.org/plugins/sfFormExtraPlugin ). If you find any annoyances / bugs just let me know.
tableName: blog_post
actAs:
Timestampable:
Sluggable: { fields: [title]}
options:
collate: utf8_unicode_ci
charset: utf8
columns:
id:
type: integer
primary: true
autoincrement: true
title:
type: string(255)
notnull: true
content:
type: clob
notnull: true
excerpt:
type: clob
notnull: true
relations:
Tags:
class: Tag
local: blog_post_id
foreign: tag_id
type: many
foreignType: many
foreignAlias: BlogPosts
refClass: BlogPostTag
#------------------- Connection for publication -> tags --------------------
BlogPostTag:
tableName: blog_post_tag
options:
collate: utf8_unicode_ci
charset: utf8
columns:
blog_post_id:
type: integer
primary: true
tag_id:
type: integer
primary: true
#------------------- Tag --------------------
Tag:
tableName: tag
options:
collate: utf8_unicode_ci
charset: utf8
actAs:
Sluggable: { fields: [name]}
columns:
id:
type: integer
primary: true
autoincrement: true
name:
type: string(255)
For the applications depending on i18n.
tableName: blog_post
actAs:
Timestampable:
I18n:
fields: [title, content, excerpt]
actAs:
Sluggable: { fields: [title], uniqueBy: [lang, title] }
options:
collate: utf8_unicode_ci
charset: utf8
columns:
id:
type: integer
primary: true
autoincrement: true
title:
type: string(255)
notnull: true
content:
type: clob
notnull: true
excerpt:
type: clob
notnull: true
relations:
Tags:
class: Tag
local: blog_post_id
foreign: tag_id
type: many
foreignType: many
foreignAlias: BlogPosts
refClass: BlogPostTag
#------------------- Connection for publication -> tags --------------------
BlogPostTag:
tableName: blog_post_tag
options:
collate: utf8_unicode_ci
charset: utf8
columns:
blog_post_id:
type: integer
primary: true
tag_id:
type: integer
primary: true
#------------------- Tag --------------------
Tag:
tableName: tag
options:
collate: utf8_unicode_ci
charset: utf8
actAs:
I18n:
fields: [name]
actAs:
Sluggable: { fields: [name], uniqueBy: [lang, name] }
columns:
id:
type: integer
primary: true
autoincrement: true
name:
type: string(255)
Similar, if not identical, use as sfWidgetFormJQueryAutocompleter, applying a renderer class by doing so: /lib/form/doctrine/BlogPostForm.class.php
class BlogPostForm extends BaseBlogPostForm { public function configure() { $autocompleteWidget = new sfWidgetFormChoice(array( 'multiple' => true, 'choices' => $this->getObject()->getTags(), 'renderer_class' => 'sfWidgetFormJQueryAutocompleterMany', 'renderer_options' => array( 'config' => '{ json_url: "'.sfContext::getInstance()->getController()->genUrl('tag/autocomplete').'", json_cache: true, filter_hide: true, filter_selected: true, maxshownitems: 8 }') )); $this->widgetSchema['tags_list'] = $autocompleteWidget; } }
If you support more than one languages / i18n use this set up instead:
class BlogPostForm extends BaseBlogPostForm { public function configure() { $autocompleteWidget = new sfWidgetFormChoice(array( 'multiple' => true, 'choices' => $this->getObject()->getTags(), 'renderer_class' => 'sfWidgetFormJQueryAutocompleterMany', 'renderer_options' => array( 'config' => '{ json_url: "'.sfContext::getInstance()->getController()->genUrl('tag/autocomplete').'", json_cache: true, filter_hide: true, culture: "'.$this->getCulture().'", filter_selected: true, maxshownitems: 8 }') )); $this->widgetSchema['tags_list'] = $autocompleteWidget; } protected function getCulture() { return isset($this->options['culture']) ? $this->options['culture'] : sfContext::getInstance()->getUser()->getCulture(); } }
While browsing a website you could have opened several windows/tabs and change the language in one of them. Then the session for the culture is changed. If the page with the autocompleter is not the one with the changed language the new suggestions will be made for the new language which is wrong. To maintain persistent culture before form submission use the method provided plus the configuration option for the javascript of the widget "culture".
Our module is Tag, our action: autocomplet stating this: /modules/tag/actions/actions.class.php
public function executeAutocomplete(sfWebRequest $request) { $this->getResponse()->setHttpHeader('Content-Type','application/json; charset=utf-8'); $tags = Tag::retrieveSuggestions($request->getParameter('q'), $request->getParameter('l'),$request->getParameter('c')); return $this->renderText(json_encode($tags)); }
Our model method used here is retrieveSuggestions : /lib/model/doctrine/Tag.class.php
static public function retrieveSuggestions($q, $l,$c) { $tags = Doctrine_Query::create() ->select('t.*,LOCATE(:token_raw,t.name) AS index') ->from('Tag t') ->where('t.name LIKE :token') ->orderBy('index') ->limit($l) ->execute(array('token_raw' => $q , 'token' => '%'.$q.'%')); $jsonTags = array(); foreach ($tags as $tag) { $jsonTags[] =array('caption' => (string) $tag->Translation[$culture]->name,'value'=> $tag->getPrimaryKey()) ; } return $jsonTags; }
And again for the i18ned applications:
static public function retrieveSuggestions($q, $l, $c) { $culture = ($c!=null) ? $c : sfContext::getInstance()->getUser()->getCulture(); $tags = Doctrine_Query::create() ->select('t.id,tr.name,LOCATE(:token_raw,tr.name) AS index') ->from('Tag t') ->leftJoin('t.Translation tr') ->where('tr.lang = :culture AND tr.name LIKE :token') ->orderBy('index') ->limit($l) ->execute(array('culture' => $culture,'token_raw' => $q , 'token' => '%'.$q.'%')); $jsonTags = array(); foreach ($tags as $tag) { $jsonTags[] =array('caption' => (string) $tag->Translation[$culture]->name,'value'=> $tag->getPrimaryKey()) ; } return $jsonTags; }
The important part here is that you return array with pair of keys:
value
caption
If you omit key names or use numerical keys it won't work.
The beloved end.