I am new to the symfony framework. I've worked on an already existing project so I want change
a selectbox into a textbox using symfony 1.2.
Some more information and code snippets would have helped but..
There are several places this could be achieved, I will go for the 2 most direct and hopefully, common.
1)
Your form has already been customised and will likely live in plugins/yourPlugin/lib/form/yourForm.class.php
In here there will be something like $this->setWidget('my_input', new sfWidgetChoice(array([...])));
There are many "Choice" widgets it may be (Doctrine or Propel if they come from the database)
You will need to change it to $this->setWidget('my_input', new sfWidgetFormInput());
2)
Your form has not been modified before and is the generated form
You will need to go into your actions.class.php (or components.class.php) and find where it says $this->form = new yourForm();
Make a new form in plugins/yourPlugin/lib/form and make it extend your previous form.
class yourNewForm extends yourForm
Then add
public function setup()
{
$this->setWidget('my_input', new sfWidgetFormInput());
}
You will likely have to update the validator as well, or it will be expecting data in the "selct box" format.
http://www.symfony-project.org/api/1_1/sfWidgetFormInput
Related
I'm making a fairly large symfony3 application. It's my first one and I must say I'm pretty amazed by the robustness of the framework. It's an application that lets users create "events". And every event is happening in a certain "location". I have two bundles "EventBundle" and "VenueBundle". A venue can host many events so there's a one to many relation between the two. At this point I have an event creation page with a dropdown input that is automaticly filled with the venues already in the database. The EntityType field made it easy for me to implement that relation. This is an awesome symfony feature.
Because it's possible that not every venue is already in the database at the moment of creating a new event, I want to use a small "quick create venue" modal window (based on zurb-foundation) in the event creation wizard. It's to prevent users from exiting the wizard to add a new venue.
I was struggeling for the past two or three days or so to have two forms from different entities on one twig page. I have already found the answer in this question: Symfony - Two forms from two entities on the same page. But the answer raised a second question for me. I think it's easier to explain if I first show the code I'm having right now:
public function createAction(Request $request)
{
$event = new Event();
$eventForm = $this->createForm(EventType::class, $event);
$venue = new Venue();
$venueQuickForm = $this->createForm(VenueQuickType::class, $venue, array(
'action' => $this->generateUrl('massiv_venue_quickcreate')
));
$eventForm->handleRequest($request);
if($eventForm->isSubmitted() && $eventForm->isValid()) {
$event = $eventForm->getData();
$event->setPostedBy(1);
$event->setUpdatedBy(1);
$em = $this->getDoctrine()->getManager();
$em->persist($event);
$em->flush();
return $this->redirectToRoute('massiv_event_homepage');
}
$venueQuickForm->handleRequest($request);
if($venueQuickForm->isSubmitted() && $venueQuickForm->isValid()) {
$venue = $venueQuickForm->getData();
$venue->setPostedBy(1);
$venue->setUpdatedBy(1);
$em = $this->getDoctrine()->getManager();
$em->persist($venue);
$em->flush();
}
In the createForm method of the second form (venueQuickForm) I added the option "action" with a url pointing to the venue controller's quickcreate action. That was my idea, I had this already in my code before I found the answer, but kept that line to see how it would behave. It turns out it is ignored because in that quickCreateAction method I simply put a "ok" response and that page is not shown when a press the submit button. The rest of the code works fine, the venue is saved in the database.
So I am about to delete that line, but is the code above indeed the way to go? Intuitively I want to keep both codes seperate so putting the "save venue" part in the Venue controller seems locic to me or is that not the way Symfony is designed to work?
everyone. I've started using atk4 in a personal project a couple weeks ago and have been facing some difficulties since then. This specific question I want to ask is about how to make form validations when using the CRUD component shipped with the atk4 framework.
I have already tried several different solutions, none of them solving my problem.
I have a feeling that the problem here might be that the form validation happens within the call of the method $form->isSubmitted() (am I correct?). Since when using a CRUD component within a Page we don't use that way of processing the form submission, we'd have to find alternatives to it. For example, let's say I have a Page with the following init() function:
function init() {
parent::init();
// create a CRUD and set a model to it
$crud = $this->add('CRUD');
$m = $crud->setModel('Person');
if ($crud->form) {
$fn = $crud->form->getField('first_name');
$fn->validateNotNull('The first name must not be empty.');
}
}
Even though I've added the validation to the first name field, it won't be validated. I've tried several things, unsuccessfully. I tried to extend the CRUD class and reimplement the formSubmit($form) function, adding the validation there. Even if I do it, it doesn't work.
Originally (in the CRUD class), there is the function:
function formSubmit($form){
$form->update();
$this->api->addHook('pre-render',array($this,'formSubmitSuccess'));
}
I tried to iterate through the form's fields and call its validate() method, but it didn't work. Also, if I try to do alter the function (in a MyCRUD class, let's say) like below,
function formSubmit($form){
if ($form->isSubmitted()) {
$form->update();
$this->api->addHook('pre-render',array($this,'formSubmitSuccess'));
}
}
there happens an infinite loop... Could someone help me out?
[EDIT]
One last question intimately related to this one. I've just tried to do the exact same validation proposed by romanish below but, instead of adding a CRUD to a page, I was just adding a Form, and it doesn't work -- though the CRUD does work. Instead, there happens a "Error in AJAX response: SyntaxError: Unexpected token
CRUD component respects the validation you're doing inside the model. When data is entered into the form and button is clicked, $model->update() is called.
The execution continues into beforeUpdate() hook, which is the one you need to intercept.
http://agiletoolkit.org/learn/understand/model/actions
class Model_Book extends Model_Table {
function init(){
parent::init();
// .... more definitions ...
$this->addHook('beforeSave',$this);
}
function beforeSave(){
if(strlen($this['book_name']<10))
throw $this->exception('Name of the book is too short')
->setField('book_name');
}
If model is unable to save itself and will produce exception, Form automatically show it as a field error.
I have a custom class that populates a controller's action parameters based on the typehint of the parameter. This works well for documents (using public properties and setters).
My aim is to make the controller simple:
function updateAction(Article $article)
{
$dm = new DocumentManager(); // code elsewhere
$dm->merge($article);
$dm->flush();
return $this->redirect('/article/' . $article->getId());
}
The problem is that the input supplying the fields to programatically populate the Article class doesn't contain all of the properties of an Article class (perhaps the edit form only contains Title and Content, but disregards Author, etc).
I was hoping that the presence of an ID would allow the document to be merged gracefully with what is currently in the database. However, any fields that are missing at the time of a merge will be removed from the document in the database.
Is there a way to update a document in such a way that only the fields that are present (non-null, I guess) are updated?
Rather than hitting the db twice - once for the find, and once for the update, you can use a FIND_AND_UPDATE query.and do it all in one step.
See this docs page for details: http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/find-and-update.html
It seems that a clean way would be to bind the model AFTER retrieving it from the database. Something along the lines of ASP.NET MVC's UpdateModel.
function updateAction($id)
{
$dm = new DocumentManager(); // code elsewhere
$article = $dm->getRepository('Article')->find($id);
$this->updateModel($article);
$dm->flush();
return $this->redirect('/article/' . $article->getId());
}
If there are any better suggestions, feel free to answer...
How to create a multi-model form in Yii? I searched the entire documentation of Yii, but got no interesting results. Can some one give me some direction or thoughts about that? Any help will be appreciable.
In my expirience i got this solution to work and quickly understandable
You have two models for data you wish collect. Let's say Person and Vehicle.
Step 1 : Set up controller for entering form
In your controller create model objects:
public function actionCreate() {
$Person = new Person;
$Vehicle = new Vehicle;
//.. see step nr.3
$this->render('create',array(
'Person'=>$Person,
'Vehicle'=>$Vehicle)
);
}
Step 2 : Write your view file
//..define form
echo CHtml::activeTextField($Person,'name');
echo CHtml::activeTextField($Person,'address');
// other fields..
echo CHtml::activeTextField($Vehicle,'type');
echo CHtml::activeTextField($Vehicle,'number');
//..enter other fields and end form
put some labels and design in your view ;)
Step 3 : Write controller on $_POST action
and now go back to your controller and write funcionality for POST action
if (isset($_POST['Person']) && isset($_POST['Vehicle'])) {
$Person = $_POST['Person']; //dont forget to sanitize values
$Vehicle = $_POST['Vehicle']; //dont forget to sanitize values
/*
Do $Person->save() and $Vehicle->save() separately
OR
use Transaction module to save both (or save none on error)
http://www.yiiframework.com/doc/guide/1.1/en/database.dao#using-transactions
*/
}
else {
Yii::app()->user->setFlash('error','You must enter both data for Person and Vehicle');
// or just skip `else` block and put some form error box in the view file
}
You can find some examples in these two Yii wiki articles:
Yii 1.1: How to use a single form to collect data for two or more models?
Yii 1.1: How to use single form to collect data for two or more models (CActiveForm and Ajax Validation edition).
You don`t need a multi-model. The right use of the MVC pattern requires a Model that reflects your UI.
To solve it, you'll have to use a CFormModel instead of an ActiveRecord to pass the data from View to Controller. Then inside your Controller you`ll parse the model, the CFormModel one, and use the ActiveRecord classes (more than one) to save in database.
Forms Overview and Form Model chapters in Yii Definitive Guide contains some details and samples.
Another suggestions -
Also we can use Wizard Behavior, It's an extension that simplifies the handling of multi-step forms. In which we can use multi model forms for registration process flow or others.
Demo - http://wizard-behavior.pbm-webdev.co.uk/
Hey guys, I've used the Symfony admin generator for a module.
Everything is working, but when the form for my model is instantiated, I need to pass in my own option.
I could do this myself by overriding the executeNew, executeCreate functions in myModuleActions.class.php (which extends myModuleAutoActions).
But I was hoping for a neater solution?
Perhaps overriding one of the configuration classes is the way to go. I basically need to add the current sf_user object ($this->getUser) as an "sf_user" option for the form, to avoid using sfContext in the myModuleForm.
Any ideas?
Welcome to Stack Overflow, jolly18.
I would just use sfContext. For example, in my app, I have a subform that creates a new Note object and assigns the user to it. In my form's configure() I have:
$new_note->setAuthor(sfContext::getInstance()->getUser()->getUsername());
I see the book calls this "The fastest but ugly way" because it makes "a big coupling between the form and the context, making the testing and reusability more difficult." But in practice... this works well and I can move on.
if module was generated using admin-generator :
in apps/backend/modules/books/actions/actions.class.php
modify: in
executeEdit(){
//leave rest unchanged
$values=array('activity_id'=>$activity_id, 'book_id'=>$book_id, 'todo_id'=>$todo_id, 'user_id'=>$this->getUser()->getGuardUser()->getId());
$this->form = new TabelBooksForm($TabelBooks, $values);
}
modify: in
executeNew(){
//leave rest unchanged
$values=array('activity_id'=>$activity_id, 'book_id'=>$book_id, 'todo_id'=>$todo_id, 'user_id'=>$this->getUser()->getGuardUser()->getId());
$this->form = new TabelBooksForm(array(), $values);
}
in TabelBooksForm.class.php
public function configure()
{
if ($this->isNew()) {
$this->setWidget('book_id', new sfWidgetFormInputHidden());
$this->setDefault('book_id', $this->getOption('book_id'));
$this->setWidget('activity_id', new sfWidgetFormInputHidden());
$this->setDefault('activity_id', $this->getOption('activity_id'));
$this->setWidget('todo_id', new sfWidgetFormInputHidden());
$this->setDefault('todo_id', $this->getOption('todo_id'));
}
}
i've been facing this problem for a while but symfony always surprises me with some neat code that i was not aware of.
I assume you'r using sfPropelPlugin, quite standar, if you checkout the code generated in cache (note: this code will be available once you tried to open the module from the browser, so firts try to look at it so we dont get in trouble :P) you may see something like:
cache/{application_name}(generally frontend or backend)/dev(enviromnemt)/autoModule_name( look here for the module)/:
lib
action
The action folder contains an action.class.php file that defines all actions generated by the generator (executeNew, Edit, Create, Update, etc). If you look a the implementation of executeNew and executeEdit, you can see that they ask a configuration instace the actual form to display, here is an example:
public function executeNew(sfWebRequest $request)
{
$this->form = $this->configuration->getForm();
$this->PaymentOrder = $this->form->getObject();
}
The configuration var containt an instance of a configuration class defined in the lib folder i mentioned earlier. That class tweaks the form to fit the object needs (generally by setting a fresh object instance).
So here comes the magic, the classes you see in your module extend from those in cache, so by pure logic, if you modifi the getForm() method in the main module/lib folder to fit your needs, you wont have to hack forms by getting user valuer where you shouldn't.
Hope this helps!