Home » legacy support » symfony 1.2 » Generator "how do I" questions
| Generator "how do I" questions [message #66094] |
Wed, 26 November 2008 20:39  |
bidule Messages: 47 Registered: November 2008 |
Member |
|
|
Ok, there are a few of them already on this forum, but here are my questions for today about the generator.
Please forgive me if the answers are somewhere in the documentation, but I couldn't find them.
Edit: I edit inline in italics with the solutions I found
Rich text editor.
I would like to use a rich text editor. How do I do that? It seems that the syntax of the generator.yml file has changed, the 'params' attribute is not used. It seems that it goes through the sfFormExtraPlugin, but I can't find more info on how it interacts with the generator.
=> see http://www.symfony-project.org/forum/index.php/m/66209/
Admin_double_list
How do I specify that I want an admin_double_list instead of a multi-select list?
=> partially solved: not in the generator, but in the form class:
$this->widgetSchema['my_list']->setOption('renderer_class', 'sfWidgetFormSelectDoubleList'); It means that if you want to get here a double list and there a multiple select list, you probably have to define a widget for each...
I18n
Despite repeated posts here and there, I could not find the way to access i18n fields from the generator, besides the embed18n thing, which is very limiting when you have long forms.
=>I have a dirty solution, see next reply.
Multiple joins
In my database, projects and organizations are related by a many-to-many relationship, and have a relationship type (such as organization A is "prime contractor" or "sub-contractor" or "consultancy" for project B) that is specified in another table.
In a schema.yml, this looks like:
project:
id: ~
name: varchar
organization:
id: ~
name: varchar
relationship:
id: ~
name: varchar
project_organization:
id_project: { type: integer, primaryKey: true, required: true, foreignTable: project, foreignReference: id}
id_organization: { type: integer, primaryKey: true, required: true, foreignTable: organization, foreignReference: id}
id_relationship: { type: integer, primaryKey: true, required: true, foreignTable: relationship, foreignReference: id, onDelete: cascade }
What I would like to do is, in my 'project' module, display the list of prime contractors, then the list of sub-contractors, etc.
Thus, I'd need to be able to set a filter on the multiple selection widget, and make sure that each new selection will be reflected in the project_organization table with the correct relationship_id.
What would be the best way to do that?
=> nailed it, by creating a new widget:
class ProgramForm extends BaseProgramForm
{
public function configure()
{
$cd = new Criteria();
$cd->add(ProgramOrganizationPeer::RELATIONSHIP_ID, 1);
$this->widgetSchema['donors'] = new sfWidgetFormPropelChoiceMany(array('model' => 'Organization'));
$this->widgetSchema['donors']->setOption('renderer_class', 'sfWidgetFormSelectDoubleList');
$this->widgetSchema['donors']->setOption('criteria', $cd);
$this->validatorSchema['donors'] = new sfValidatorPropelChoiceMany(array('model' => 'Organization', 'required' => false));
}
+ overload updateDefaultsFromObject()
+ overload doSave()
Overload
Finally, I believe that although it is quite flexible, there's going to be a number of things the generator will not allow me to do. If I want to override some of the templates, or actions, can I just copy them from the cache, paste them in the module directory, and modify them at my will? Is that the best way to do? For example, if I'd like to display some of the fields side-by-side, do you think I'll manage to do that way, or should I just drop the generator and redo templates by myself?
Thanks for your answers
[Updated on: Fri, 28 November 2008 02:58]
|
|
|
| Re: Generator "how do I" questions [message #66221 is a reply to message #66094 ] |
Fri, 28 November 2008 03:17   |
bidule Messages: 47 Registered: November 2008 |
Member |
|
|
Ok, here is what I got for I18n. I haven't tested much more than on a few simple fields, but it seems to work so far.
It basically gets all widgets and validators from the ArticleI18nForm class and copies them to the ArticleForm class for all cultures, appending the culture to the widget names, so that we can get access to title_en field in the generator.
I'm sure it's ugly and it will eventually fail miserably, but I'd love someone to tell me, either that it's absurd and that I can do that in a far simpler manner, or that it's ok-ish but would need adjustments...
<?php class ArticleForm extends BaseArticleForm
{
private $lang = array('en', 'fr');
public function configure()
{
$this->addI18n();
}
public function addI18n()
{
foreach($this->lang as $l)
{
$f = new ArticleI18nForm();
$widgets = $f->getWidgetSchema()->getFields();
$validators = $f->getValidatorSchema()->getFields();
foreach($widgets as $name => $widget)
{
$this->setWidget($name.'_'.$l, $widget);
$this->setDefault($name.'_'.$l, $this->object->getCurrentArticleI18n($l)->getByName(sfInflector::camelize($name)));
}
foreach($validators as $name => $validator)
{
$this->setValidator($name.'_'.$l, $validator);
}
}
}
public function doSave($con = null)
{
parent::doSave($con);
if (!$this->isValid())
{
throw $this->getErrorSchema();
}
if (is_null($con))
{
$con = $this->getConnection();
}
foreach($this->lang as $l)
{
$f = new ArticleI18nForm();
$widgets = $f->getWidgetSchema()->getFields();
foreach($widgets as $name => $widget)
{
if (!isset($this->widgetSchema[$name.'_'.$l]))
{
return;
}
$value = $this->getValue($name.'_'.$l);
$c = new Criteria();
$c->add(ArticleI18nPeer::ID,$this->object->getPrimaryKey());
$c->add(ArticleI18nPeer::CULTURE,$l);
$obj = ArticleI18nPeer::doSelectOne($c, $con);
if(count($obj)==0) //we have no object for this culture
{
$obj = new ArticleI18n();
$obj->setCulture($l);
$obj->setId($id);
}
$obj->setByName(sfInflector::camelize($name), $value);
$obj->save();
}
}
}
} ?>
Thanks for your comments.
Edit:
- Changed ucWords for inflector usage.
- This does not save new rows in the i18n table properly.
- It also needs a test to exclude _crsf_Token from the widget list.
[Updated on: Thu, 04 December 2008 22:59]
|
|
|
| Re: Generator "how do I" questions [message #66906 is a reply to message #66221 ] |
Fri, 05 December 2008 16:41   |
Sylvio Messages: 58 Registered: May 2006 Location: Avignon, France |
Member |
|
|
I manage to use TinyMCE With new Admin Generator (SF1.2) in 3 steps :
1- Install sfFormExtraPlugin
2- Patch sfFormExtraPlugin/lib/widget/sfWidgetFormTextareaTinyMCE.cla ss.php
At beggining of "render()" method (L58), add the following code:
$attributes = array_merge($this->attributes, $attributes);
3- In you Form class (ex: /lib/form/NewsForm.class.php), add the following code in "configure()" method :
$this->widgetSchema['content'] = new sfWidgetFormTextareaTinyMCE(
array(
'width'=>550,
'height'=>350,
'config'=>'theme_advanced_disable: "anchor,image,cleanup,help"',
'theme' => sfConfig::get('app_tinymce_theme','advanced'),
),
array(
'class' => 'tiny_mce'
)
);
$js_path = sfConfig::get('sf_rich_text_js_dir') ? '/'.sfConfig::get('sf_rich_text_js_dir').'/tiny_mce.js' : '/sf/tinymce/js/tiny_mce.js';
sfContext::getInstance()->getResponse()->addJavascript($js_path);
Obviously, you must have before set the "rich_text_js_dir" option in settings.yml and download and copy TinyMCE in the good directory.
[Updated on: Fri, 05 December 2008 16:45] Sylvain Papet - Web Developper
Com-Océan / www.com-ocean.com
|
|
|
| Re: Generator "how do I" questions [message #66914 is a reply to message #66906 ] |
Fri, 05 December 2008 18:03   |
bidule Messages: 47 Registered: November 2008 |
Member |
|
|
Yes.
In general, I found that there are a good number of things that one could setup directly in generator.yml for the previous version (1.0), that now need to be setup in the forms.
While this makes sense when we're doing very specific things, there should be more hooks in the current version of the generator, such as:
- choosing the widget renderer,
- accessing widget styles,
- accessing i18n fields.
Overloading each and every textarea field in a big application is really a pain. Similarly for i18n: for lack of a better solution, I'm using a non-i18n data structure (localized fields in the main table instead of i18n table), which is not an option when a site has too many languages or a growing number of languages.
[Updated on: Fri, 05 December 2008 18:04]
|
|
|
| Re: Generator "how do I" questions [message #70346 is a reply to message #66906 ] |
Tue, 20 January 2009 18:36   |
sklefisch Messages: 11 Registered: August 2008 Location: Germany |
Junior Member |
|
|
Hi, i have a question about the tiny mce implementation.
it works fine for me if i use only one instance of the tinymice. but in my case i need two.
i have a i18n table text_snippet and text_snippet_i18n. in my admin it looks like pic1 if i use only one tiny mce. if i activate the second one, it looks like pic2 and the text in the first is not visible but still in the html code.
here is the form code:
public function configure()
{
$this->embedI18n(array('de_DE', 'en_US'));
$this->widgetSchema['de_DE']['text'] = new sfWidgetFormTextareaTinyMCE(
array(
'width'=>550,
'height'=>350,
'config'=>'theme_advanced_disable: "anchor,image,cleanup,help"',
'theme' => sfConfig::get('app_tinymce_theme','advanced'),
),
array(
'class' => 'tiny_mce'
)
);
$this->widgetSchema['en_US']['text'] = new sfWidgetFormTextareaTinyMCE(
array(
'width'=>550,
'height'=>350,
'config'=>'theme_advanced_disable: "anchor,image,cleanup,help"',
'theme' => sfConfig::get('app_tinymce_theme','advanced'),
),
array(
'class' => 'tiny_mce'
)
);
any ideas why this is not working?
Stefan

Attachment: pic1.jpg
(Size: 40.55KB, Downloaded 4679 time(s))
Attachment: pic2.jpg
(Size: 38.17KB, Downloaded 4613 time(s))
|
|
| | |
| Re: Generator "how do I" questions [message #71206 is a reply to message #66094 ] |
Sun, 01 February 2009 22:20   |
kaleanych Messages: 1 Registered: June 2008 |
Junior Member |
|
|
Hello,
Here is how i made it. Not sure if this is the best way, but it works.
class xTermForm extends BasexTermForm
{
public function configure()
{
$this->widgetSchema['def'] = new sfWidgetFormTextareaTinyMCE(
array(
'width'=>500,
'height'=>150,
'config'=>'theme_advanced_disable: "anchor,image,cleanup,help", elements: "x_term_def", mode: "exact"',
'theme' => sfConfig::get('app_tinymce_theme','advanced'),
),
array(
'class' => 'tiny_mce',
'id' => 'x_term_def',
)
);
$this->widgetSchema['source'] = new sfWidgetFormTextareaTinyMCE(
array(
'width'=>500,
'height'=>150,
'config' => 'elements: "x_term_source", mode: "exact", theme_toolbar_align: "center"',
'theme' => 'simple',
),
array(
'class' => 'tiny_mce',
'id' => 'x_term_source',
)
);
$js_path = sfConfig::get('sf_rich_text_js_dir') ? '/'.sfConfig::get('sf_rich_text_js_dir').'/tiny_mce.js' : '/tinymce/jscripts/tiny_mce/tiny_mce.js';
sfContext::getInstance()->getResponse()->addJavascript($js_path);
}
}
and here is the sfWidgetFormTextareaTinyMCE from sfFormExtraPlugin:
class sfWidgetFormTextareaTinyMCE extends sfWidgetFormTextarea
{
/**
* Constructor.
*
* Available options:
*
* * theme: The Tiny MCE theme
* * width: Width
* * height: Height
* * config: The javascript configuration
*
* @param array $options An array of options
* @param array $attributes An array of default HTML attributes
*
* @see sfWidgetForm
*/
protected function configure($options = array(), $attributes = array())
{
$this->addOption('theme', @$options['theme'] ? $options['theme'] : 'advanced');
//$this->addOption('mode', @$options['mode'] ? $options['mode'] : 'textareas');
$this->addOption('width');
$this->addOption('height');
$this->addOption('config', '');
}
/**
* @param string $name The element name
* @param string $value The value selected in this widget
* @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
* @param array $errors An array of errors for the field
*
* @return string An HTML tag string
*
* @see sfWidgetForm
*/
public function render($name, $value = null, $attributes = array(), $errors = array())
{
$attributes = array_merge($this->attributes, $attributes);
if (!isset($attributes['class']))
{
throw new InvalidArgumentException(sprintf('You must pass a "class" attribute for a TinyMCE widget (%s).', $name));
}
$textarea = parent::render($name, $value, $attributes, $errors);
// take the first class
$classes = explode(' ', $attributes['class']);
$class = trim($classes[0]);
$js = sprintf(<<<EOF
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "%s",
editor_selector: "%s",
%s
%s
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
%s
});
</script>
EOF
,
//$this->getOption('mode'),
$this->getOption('theme'),
$class,
$this->getOption('width') ? sprintf('width: "%spx",', $this->getOption('width')) : '',
$this->getOption('height') ? sprintf('height: "%spx",', $this->getOption('height')) : '',
$this->getOption('config') ? ",\n".$this->getOption('config') : ''
);
return $textarea.$js;
}
}
You can customize it however you want, but important is to give textarea an ID and point the "elements" property of TinyMCE to this ID, as well as to set the "mode" property of TinyMCE to "exact".
I'll look around for a better solution, if it exists. 
|
|
| |
Goto Forum:
|