Symfony: exclude empty values from form save - forms

I have a many to many relation between Product and Properties. I'm using embedRelation() in my Product form to edit a Product and it's Properties. Properties includes images which causes my issue. Every time I save the form the updated_at column is updated for file properties even when no file is uploaded.
Therefore, I want to exclude empty properties when saving my form.
I'm using Symfony 1.4 and Doctrine 1.2.
I'm thinking something like this in my ProductForm.class.php, but I need some input on how to make this work.
Thanks
class ProductForm extends BaseProductForm
{
public function configure()
{
unset($this['created_at'], $this['updated_at'], $this['id'], $this['slug']);
$this->embedRelation('ProductProperties');
}
public function saveEmbeddedForms($con = null, $forms = null)
{
if (null === $forms)
{
$properties = $this->getValue('ProductProperties');
$forms = $this->embeddedForms;
foreach($properties as $p)
{
// If property value is empty, unset from $forms['ProductProperties']
}
}
}
}

I ended up avoiding Symfony's forms and saving models instead of saving forms. It can be easier when playing with embedded forms. http://arialdomartini.wordpress.com/2011/04/01/how-to-kill-symfony%E2%80%99s-forms-and-live-well/

Solved it by checking if posted value is a file, and if both filename and value_delete is null I unset from the array. It might not be best practice, but it works for now.
Solution based on http://www.symfony-project.org/more-with-symfony/1_4/en/06-Advanced-Forms
class ProductPropertyValidatorSchema extends sfValidatorSchema
{
protected function configure($options = array(), $messages = array())
{
// N0thing to configure
}
protected function doClean($values)
{
$errorSchema = new sfValidatorErrorSchema($this);
foreach($values as $key => $value)
{
$errorSchemaLocal = new sfValidatorErrorSchema($this);
if(array_key_exists('value_delete', $values))
{
if(!$value && !$values['value_delete'])
{
unset($values[$key]);
}
}
// Some error for this embedded-form
if (count($errorSchemaLocal))
{
$errorSchema->addError($errorSchemaLocal, (string) $key);
}
}
// Throws the error for the main form
if (count($errorSchema))
{
throw new sfValidatorErrorSchema($this, $errorSchema);
}
return $values;
}
}

Related

database query according to file input empty or not in codeigniter

So i am changing my project from core PHP to Codeigniter. I have a edit for in which their are 3 input type file. Now i want to run my query according to these inout file. like if input file 1 is empty than don't update value else update. I did it in core PHP like this:
The name of input type file are: image1, image2, image3
mysqli query in core PHP:
if(!empty($photo1))
{
$p1=str_replace("-","",time().$photo1);
move_uploaded_file($_FILES['photo1']['tmp_name'], $folder.$p1);
$query .=",`image1`='$p1'";
}
if(!empty($photo2))
{
$p2=str_replace("-","",time().$photo2);
move_uploaded_file($_FILES['photo2']['tmp_name'], $folder.$p2);
$query .=",`image2`='$p2'";
}
if(!empty($photo3))
{
$p3=str_replace("-","",time().$photo3);
move_uploaded_file($_FILES['photo3']['tmp_name'], $folder.$p3);
$query .=",`image3`='$p3'";
}
Now how to do this in codeigniter model:
controller
public function store_ad()
{
$id=$this->input->post('id');
$d_email=$this->session->userdata('dealer_email');
$p_type=$this->input->post('property_type');
$p_subtype=$this->input->post('property_subtype');
$p_for=$this->input->post('p_for');
$p_name=$this->input->post('p_name');
$p_price=$this->input->post('p_price');
$state=$this->input->post('state');
$city=$this->input->post('city');
$loc=$this->input->post('location');
$pincode=$this->input->post('pincode');
$about=$this->input->post('p_about');
$stat=$this->input->post('status');
$config['upload_path'] = './images/properties';
$config['allowed_types']='gif|png|jpeg|jpg';
$this->load->library('upload',$config);
if($this->upload->do_upload('image1'))
{
$data1=$this->upload->data();
$img1=$data1['raw_name'].$data1['file_ext'];
}
if($this->upload->do_upload('image2'))
{
$data2=$this->upload->data();
$img2=$data2['raw_name'].$data2['file_ext'];
}
if($this->upload->do_upload('image3'))
{
$data3=$this->upload->data();
$img3=$data3['raw_name'].$data3['file_ext'];
}
}
How to crearte model according to the non empty input file. I am storing the name of the file in database
Inside your method in the model class check if the files you want to upload is empty or not e.g
public function update($data_array, $img1, $img2, $img3){
if(!empty($img1)){
$data_array['img_column1'] = $img1;
}
if(!empty($img2)){
$data_array['img_column2'] = $img2;
}
if(!empty($img3)){
$data_array['img_column3'] = $img3;
}
return $this->db->insert('YOUR_TABLE_NAME', $data_array);
}
Hope this helps....

Doctrine EventListener onFlush access to old Document

I can access to the updated document in onFlush eventListerner of Doctrine2.
I want complete old document to store it elsewhere as old state.
public function onFlush(OnFlushEventArgs $eventArgs)
{
$dm = $eventArgs->getDocumentManager();
$uow = $dm->getUnitOfWork();
foreach ($uow->getScheduledDocumentUpdates() as $document) {
// $document is updated document
// $changeSet contains only new and old values
$changeSet = $uow->getDocumentChangeSet($document);
// I want the whole old document object as $oldDocument
}
}
How can I access old document not just change set?
Just use the preUpdate event. Example:
public function preUpdate(PreUpdateEventArgs $event)
{
$entity = $event->getEntity(); // the whole entity
$changeSet = $event->getEntityChangeSet(); // only changed properties
// check if password has been changed
if ($event->hasChangedField('password')) {
// do stuff
}
/* ... */
}

sf 1.4 Access & customize embededObject() in root form

I got a problem to save custom values for embededforms in root form.
I can actually edit a "manifestation" and i can add as much as i want "commande_wifi".
Everything is good saved.
I need to customize the process for every "commande_wifi" ( there is a 'puht' value depending on other values of the object() ). I have already lost a few hours only to do that.
save() is only called on the root form
That’s right! Only the root form has save() called. So if there’s other logic you want to run, you will want to override the saveEmbeddedForm method and call that code before. Oversimplification ahead: when you save a form with embedded forms, it calls $this->getObject()->save(), then it calls saveEmbeddedForms, which, for each embedded form, calls $form->saveEmbeddedForms() and then calls $form->getObject()->save(). This is critical to know, as it will save you a lot of headaches later on.
http://jmather.com/2011/01/29/6-things-to-know-about-embedded-forms-in-symfony/
I've tried to overwrite the saveembededForms() but fail at this point.
class manifestationForm extends BasemanifestationForm
{
public function configure()
{
$this->embedRelation('commande_wifi');
}
public function addNewFields($number){
$new_commandes = new BaseForm();
for($i=0; $i <= $number; $i+=1){
$commande = new Commande_wifi();
$commande->setManifestation($this->getObject());
$commande_form = new commande_wifiForm($commande);
$new_commandes->embedForm($i,$commande_form);
}
$this->embedForm('new', $new_commandes);
}
public function bind(array $taintedValues = null, array $taintedFiles = null){
$new_commandes = new BaseForm();
foreach($taintedValues['new'] as $key => $new_commande){
$commande = new Commande_wifi();
$commande->setManifestation($this->getObject());
$commande_form = new commande_wifiForm($commande);
$new_commandes->embedForm($key,$commande_form);
}
$this->embedForm('new',$new_commandes);
parent::bind($taintedValues, $taintedFiles);
}
public function saveEmbeddedForm($con = null, $forms = null)
{
if ($con === NULL)
{
$con = $this->getConnection();
}
if ($forms === NULL)
{
$forms = $this->getEmbeddedForms();
}
foreach ($forms as $form)
{
if ($form instanceof sfFormObject)
{
$form->saveEmbeddedForms($con);
$form->getObject()->setPuht(99);
$form->getObject()->save($con);
}
else
{
$this->saveEmbeddedForms($con, $form->getEmbeddedForms());
}
//$form->getObject()->setPuht(99)->save();
}
}
}
It's won ASAP i can access the embedForm Object().
Any suggestion?

CakePHP SET error => false FOR All Forms

I want to handle application feedback regarding, in this case, form validation.
To do this I check for model validation in controller, using
// VALIDATE
if ($this->Event->validates($this->data))
{
// SAVE
$this->Event->create();
if ($this->Event->saveAll($this->data, array('validate' => false)))
{
$this->Session->setFlash('Evenimentul a fost salvat!', 'flash_admin_success');
$this->redirect(array('action' => 'index', 'admin' => true));
} else {
$this->Session->setFlash('Evenimentul nu a putut fi salvat. Va rugam sa incercati din nou!', 'flash_admin_error');
}
////////
$errors = 'O EROARE';
$this->set(compact('errors'));
}
else
{
// GET ERRORS to display it nicely :)
$errors = $this->Event->invalidFields();
$flash = '';
foreach($errors as $error)
{
$flash .= $error."<br />";
}
$this->Session->setFlash($flash, 'flash_admin_error');
}
I know that there is a way to get rid of form field errors using 'error' => false, but i want to set this for the entire application, thus for all fields in all forms.
It has to be there a way of setting that fot the object itself, and I would be gratefull if someone would tell me.
Thaks a lot!
Edit: This doesn't really disable error output, but will hide the error: go to webroot/css/cake.generic.css add display:none to selector div.error-message. That's the simplest way to achieve what you want that I can think of.
Though it may seem like a bit of an extreme approach to override a single property, you can achieve this by extend the core FormHelper. This will allow you to make Anh Pham's original suggestion the default for all FormHelper instances:
// app/views/helpers/app_form.php
App::import('Helper', 'Time');
class AppFormHelper extends FormHelper {
public $_inputDefaults = array('error' => false);
}
Now to use this as-is in CakePHP 1.3, you would have to use "AppForm" throughout your application to refer to this helper from now on (ie. $this->AppForm->input()). CakePHP 2.0 introduces helper aliasing to overcome this, but for now one has to resort to a bit of trickery to continue using "Form" instead. One blog post I found shows how to backport the functionality and another manages allow the helper to do it itself. I personally use the following without any problems:
// app/views/app.php
class AppView extends View {
function &_loadHelpers(&$loaded, $helpers, $parent = null) {
$return = parent::_loadHelpers($loaded, $helpers, $parent);
# rename App helpers (ie. AppHtml -> Html)
foreach ($return as $helperName => $helper) {
if (substr($helperName, 0, 3) === 'App') {
$newHelperName = substr($helperName, 3);
$return[$newHelperName] = $return[$helperName];
}
}
# done
return $return;
}
}
To use the new created classes above, just add the following to your AppController:
// app/app_controller.php
class AppController extends Controller {
public $helpers = array(/*...*/, 'AppForm');
public $view = array('App');
}

Indexing Adds/Changes not working using Lucene in Zend Framework

I am pretty new to programming and definitely to Zend/Lucene indexing. From what I can tell, though, my code is correct. I feel like I may be overlooking a step or something trying to upload changes and adds to the database so that they appear in the search on my website. I'm not getting any kind of an error message though. Below is the code from the controller. I guess let me know if you need anything else to help this make sense. Thanks in advance for any direction you can give.
class SearchController extends Zend_Controller_Action
{
public function init()
{
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity()) {
$this->view->identity = $auth->getIdentity();
}
}
public function indexAction()
{
// action body
}
public function buildAction()
{
// create the index
$index = Zend_Search_Lucene::open(APPLICATION_PATH . '/indexes');
$page = $this->_request->getParam('page');
// build product pages
if ($page == 'search') {
$mdl = new Model_Search();
$search = $mdl->fetchAll();
if ($search->count() > 0) {
foreach ($search as $s) {
$doc = new Zend_Search_Lucene_Document();
$doc->addField(Zend_Search_Lucene_Field::unIndexed('id', $s->id));
$doc->addField(Zend_Search_Lucene_Field::text('name', $s->name));
$doc->addField(Zend_Search_Lucene_Field::text('uri', $s->uri));
$doc->addField(Zend_Search_Lucene_Field::text('description', $s->description));
$index->addDocument($doc);
}
}
$index->optimize();
$this->view->indexSize = $index->numDocs();
}
}
public function resultsAction()
{
if($this->_request->isPost()) {
$keywords = $this->_request->getParam('query');
$query = Zend_Search_Lucene_Search_QueryParser::parse($keywords);
$index = Zend_Search_Lucene::open(APPLICATION_PATH . '/indexes');
$hits = $index->find($query);
$this->view->results = $hits;
$this->view->keywords = $keywords;
} else {
$this->view->results = null;
}
}
}
Lucene indexes won't stay in sync with your database automatically, you either need to rebuild the entire index or remove and re-add the relevant documents when they change (you cannot edit an existing document).
public function updateAction()
{
// something made the db change
$hits = $index->find("name: " . $name);
foreach($hits as $hit) {
$index->delete($hit->id)
}
$doc = new Zend_Search_Lucene_Document();
// build your doc
$index->add($doc);
}
Note that lucene documents had their own internal id property, and be careful not to mistake it for an id keyword that you provide.