First : sorry for my long message.
I'm trying to learn Fuel, but I have some problems with Fieldset class and Orm.
I've create a Model which extends ORM, in order to get an automatic generated form, according to my database.
My Model
class Model_Product extends \Orm\Model
{
protected static $_table_name = 'products';
protected static $_properties = array(
'id' => array(
'data_type' => 'int'
),
'name' => array(
'data_type' => 'varchar',
'label' => 'Name',
'validation' => array(
'required', 'trim', 'max_length'=>array(30), 'min_length'=>array(3)
),
),
'description' => array(
'data_type' => 'varchar',
'label' => 'Description',
'validation' => array(
'max_length' => array(290)
),
'form' => array(
'type' => 'textarea'
),
),
'price' => array(
'data_type' => 'integer',
'label' => 'Price',
'validation' => array(
'required', 'trim', 'valid_string' => array('numeric','dots')
),
),
'pic' => array(
'data_type' => 'varchar',
'label' => 'Path to the pic',
'validation' => array(
'required', 'trim'
),
),
'registered' => array(
'data_type' => 'date',
'label' => 'Registration date',
'validation' => array(
'required', 'trim'
) //'valid_string' => array('numeric','dashes')
),
);
} //end of class Model_Product
Then I create the controller which will validate the form.
My function from the controller
function action_add()
{
$fieldset = Fieldset::forge('add_product')->add_model('Model_Product')->repopulate();
$form = $fieldset->form();
$form->add('submit', '', array('type' => 'button', 'value' => 'Add item', 'class' => 'button-link' ));
$validation = $fieldset->Validation();
if($validation->run() === true)
{
$fields = $fieldset->validated();
//create a new Product, with validated fields
$product = new Model_Product;
$product->name = $fields['name'];
$product->description = $fields['description'];
$product->price = $fields['price'];
$product->pic = $fields['pic'];
$product->registered = $fields['registered'];
try
{
//if the product is successfully inserted in the database
if($product->save())
{
Session::set_flash('success', 'Product successfully added !');
\Response::redirect('products/product_details/'.$product->id);
}
}
catch(Exception $e)
{
Session::set_flash('error', 'Unable to save the product into the database !'.$e->getMessage());
}
}
//If the validation doesn't pass
else
{
Session::set_flash('error', $fieldset->show_errors());
}
$this->template->set('content', $form->build(), false);
} // end of method add()
My first question :
How and where in my function from controller can i add a 'fieldset' tag with a specific class, in order to 'beautify' my auto-generated form ?
Let's say
<fieldset class="add_product">
Second question :
What do I have to do in order to correctly validate de 'price' field, because in MySQL is set as decimal(5,2), but when I'm trying to validate with my actual validation rule, it doesn't pass (it works only with integer values Ex.: 42, but not with decimal Ex.: 42.35). I have tried to change the type from 'integer' to 'double', but it doesn't work .
If you can point to some specific documentation regarding my problems, which I possible didn't read yet, please do feel free.
Gabriel
I can answer the first question To change the automatically generated form you will need to copy fuel/core/config/form.php to the fuel/app/config directory and edit this file to suit your needs.
Related
class Module_PhotoController extends Core_Controller_Action_Standard
{
public function nameAction()
{
$this->view->form = $form = new Modulename_Form_Fromname();
$this->addElement('Text', 'sender', array(
'label' => 'Send to',
'maxlength' => '40',
'filters' => array(
//new Engine_Filter_HtmlSpecialChars(),
'StripTags',
new Engine_Filter_Censor(),
new Engine_Filter_StringLength(array('max' => '63')),
)
));
}
}
Try this code
$form->addElement('Text', 'sender', array(
'label' => 'Send to',
'maxlength' => '40',
'filters' => array(
//new Engine_Filter_HtmlSpecialChars(),
'StripTags',
new Engine_Filter_Censor(),
new Engine_Filter_StringLength(array('max' => '63')),
)
));
Proper way to do this is to edit file that's in /application/modules/Modulename/Form/Fromname.php and use addElement to add specific elements to the form. Constructing forms in controllers isn't best SE programming practice.
I am using the Zend Framework 2 and notice my sql queries are running twice when pulling values from the database to use in my Forms. I can see in the developertool that it is running twice (two different run times). It only happens with the form elements (not when I echo query results into a table)
I used the below link as a guide:
http://samminds.com/2013/03/zendformelementselect-and-database-values/
Thanks
M
Controller Action
public function indexAction() //Display the pro greetings page
{
$this->layout()->setVariable('menu', 'verified');
$dbAdapter = $this->getServiceLocator()->get('Zend\Db\Adapter\Adapter');
$form = new ProLicenceForm($dbAdapter);
$form->get('submit')->setValue('Submit');
$pro_id='22';
$proBackEnd = new ProSide($dbAdapter);
$form->get('pro_id')->setValue($pro_id);
// $user_id=$this->zfcUserAuthentication()->getIdentity()->getId(); //causes error if not register need to block or add logic to redirect
// $form->get('user_id')->setValue($user_id); //pass the user id from the user module
$request = $this->getRequest();
if ($request->isPost()) {
$proLicence = new ProLicence();
$form->setInputFilter($proLicence->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$proLicence->exchangeArray($form->getData());
$this->getProLicenceTable()->saveProLicence($proLicence);
// return $this->redirect()->toRoute('pro', array('action'=>'proVerification')); //redirect to next step
}
else {
echo "ERROR HOMMIE";
}
}
return array(
'form' => $form,
'proLicences' => $proBackEnd->getProSideLicence($pro_id),
);
}
Form
<?php
namespace Pro\Form;
use Zend\Form\Form;
use Zend\Db\Adapter\AdapterInterface;
class ProLicenceForm extends Form
{
public function __construct(AdapterInterface $dbAdapter)
{
// $this->setDbAdapter($dbAdapter);
$this->adapter =$dbAdapter;
// we want to ignore the name passed
parent::__construct('pro-licence-form');
$this->add(array(
'name' => 'pro_id',
'type' => 'Hidden',
));
$this->add(array(
'name' => 'licence_id',
'type' => 'Hidden',
'options' => array(
),
'attributes' => array(
//'required' => 'required'
)
));
$this->add(array(
'name' => 'licence_name_id',
'type' => 'Zend\Form\Element\Select',
'options' => array(
'label' => 'Licence',
'value_options' => $this->getLicenceOptions(),
'empty_option' => '--- please choose ---'
),
'attributes' => array(
'placeholder' => 'Choose all that apply'
)
));
$this->add(array(
'name' => 'licence_number',
'type' => 'Text',
'options' => array(
'label' => 'Licence Number'
)
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'options' => array(
'label'=> 'Primary Button',
),
'attributes' => array(
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
/*
* SQL statements used to bring in optiosn
*/
public function getLicenceOptions()
{
$dbAdapter = $this->adapter;
$sql = 'SELECT licence_name_id,licence_name FROM licence_name_table ORDER BY licence_name';
$statement = $dbAdapter->query($sql);
$result = $statement->execute();
$selectData = array();
foreach ($result as $res) {
$selectData[$res['licence_name_id']] = $res['licence_name'];
}
return $selectData;
}
}
The Zend quickstart guide:
http://framework.zend.com/manual/2.2/en/modules/zend.form.quick-start.html
Implies that the form factory can attach the filters automatically by adding them to the configuration array, rudimentary testing demonstrates that validation is occurring, but nothing is getting passed back to the view ( formElementErrors or formRow ).
)
Factory Array
$this->form = array(
'hydrator' => 'Zend\Stdlib\Hydrator\ArraySerializable',
'elements' => array(
array(
'spec' => array(
'name' => 'name',
'options' => array(
'label' => 'Your name',
),
'attributes' => array(
'type' => 'text'
),
)
),
array(
'spec' => array(
'type' => 'Zend\Form\Element\Email',
'name' => 'email',
'options' => array(
'label' => 'Your email address',
)
),
),
array(
'spec' => array(
'type' => 'Zend\Form\Element\Csrf',
'name' => 'security',
),
),
array(
'spec' => array(
'name' => 'send',
'attributes' => array(
'type' => 'submit',
'value' => 'Submit',
),
),
),
),
'input_filter' => array(
'name' => array(
'required' => true,
'filters' => array(
array('name' => 'Zend\Filter\StringTrim'),
),
),
'email' => array(
'required' => true,
'filters' => array(
array('name' => 'Zend\Filter\StringTrim'),
),
'validators' => array(
new Validator\EmailAddress(),
),
)
)
);
Controller
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Form\Factory;
use Application\Form\Login;
class LoginController extends AbstractActionController
{
public function indexAction()
{
$factory = new Factory();
$login = new Login();
$form = $factory->createForm($login->form);
if ($this->getRequest()->isPost())
{
$form->setData( $this->getRequest()->getPost() );
/*
if ($form->isValid())
{
die('valid');
}
else
{
die('invalid');
}
*/
}
return(array('form' => $form));
}
public function loginAction()
{
die('login');
}
}
View
<?php
$form = $this -> form;
$form -> prepare();
$form -> setAttribute('method', 'post');
$formLabel = $this -> plugin('formLabel');
echo $this -> form() -> openTag($form);
?>
<div class="form_element">
<?php echo $this -> formRow($form -> get('name'));?>
</div>
<div class="form_element">
<?php echo $this -> formRow($form -> get('email')); ?>
</div>
<?php echo $this->formElement($form -> get('security')); ?>
<?php echo $this->formElement($form -> get('send')); ?>
<?php echo $this->form()->closeTag(); ?>
This is a quick one - I don't tend to use $this->formRow(), but I think you'll have add <?php echo $this->formElementErrors($elementInstance); ?>
into your markup
From http://framework.zend.com/manual/2.2/en/modules/zend.form.quick-start.html
"Validating forms requires three steps. First, the form must have an input filter attached. Second, you must inject the data to validate into the form. Third, you validate the form. If invalid, you can retrieve the error messages, if any."
I had wrongly assumed that the validation would automatically attach the feedback to the form. The code below attaches error messages if required.
Thanks to all SO users that took interest.
if ($form->isValid()) {
$validatedData = $form->getData();
// Do something useful
} else {
$messages = $form->getMessages();
}
Having just arrived at Prestashop 1.5, I am making a very simple module: a video of the week, associated with multiple products that need to appear right next to it.
I decided to start from the Backoffice. Right now, I can view, add, edit and remove all the Video entries but I'm a bit lost on how to map the N-N association between a video and its related products... The lack of documentation isn't helping either.
Any ideas how to pull this off?
Here's a bit of my code, the Video class is defined by:
class Video extends ObjectModel {
public $id_video;
public $title;
public $url;
public $active;
public static $definition = array(
'table' => 'video',
'primary' => 'id_video',
'multilang' => false,
'fields' => array(
'id_video' => array(
'type' => ObjectModel :: TYPE_INT
),
'title' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'url' => array(
'type' => ObjectModel :: TYPE_STRING,
'required' => true
),
'active' => array(
'type' => ObjectModel :: TYPE_BOOL,
'required' => true
)
),
);
(...)
and the AdminVideo class is here:
class AdminVideoController extends ModuleAdminController {
public function __construct()
{
$this->table = 'video';
$this->className = 'Video';
$this->lang = false;
$this->fields_list['id_video'] = array(
'title' => $this->l('ID'),
'align' => 'center',
);
$this->fields_list['title'] = array(
'title' => $this->l('Title'),
'width' => 'auto'
);
$this->fields_list['url'] = array(
'title' => $this->l('URL'),
'width' => 'auto'
);
$this->fields_list['active'] = array(
'title' => $this->l('Active'),
'width' => '70',
'align' => 'center',
'active' => 'status',
'type' => 'bool',
'orderby' => false
);
parent::__construct();
}
public function postProcess()
{
parent::postProcess();
}
public function renderList()
{
$this->addRowAction('edit');
$this->addRowAction('delete');
$this->addRowAction('details');
return parent::renderList();
}
public function renderForm()
{
if (!($obj = $this->loadObject(true)))
return;
$this->fields_form = array(
'legend' => array(
'title' => $this->l('This weeks video'),
'image' => '../img/admin/world.gif'
),
'input' => array(
array(
'type' => 'text',
'label' => $this->l('Nome'),
'name' => 'title',
'size' => 33,
'required' => true,
'desc' => $this->l('Title')
),
array(
'type' => 'text',
'label' => $this->l('URL'),
'name' => 'url',
'size' => 33,
'required' => true,
'desc' => $this->l('Video URL')
),
array(
'type' => 'radio',
'label' => $this->l('Active:'),
'name' => 'active',
'required' => false,
'class' => 't',
'is_bool' => true,
'values' => array(
array(
'id' => 'active_on',
'value' => 1,
'label' => $this->l('Enabled')
),
array(
'id' => 'active_off',
'value' => 0,
'label' => $this->l('Disabled')
)
),
'desc' => $this->l('Only one video can be active at any given time')
),
)
);
if (Shop::isFeatureActive())
{
$this->fields_form['input'][] = array(
'type' => 'shop',
'label' => $this->l('Shop association:'),
'name' => 'checkBoxShopAsso',
);
}
$this->fields_form['submit'] = array(
'title' => $this->l(' Save '),
'class' => 'button'
);
if (!($obj = $this->loadObject(true)))
return;
return parent::renderForm();
}
}
One other thing: would it be possible to add a preview of the video inside the backoffice? I tried to echo YouTube's embed code, but it gets inserted even before the header. Is there a clean way of doing this or do I have to use some jQuery trickery? I was basically doing an echo of YT's embed code just before the end of postProcess().
Thanks in advance!
The simplest way to associate the videos to the products is by adding a "products" text field in your "video" table to store a comma separated list of the ids of the associated products (eg.: 1,10,27). Even if it's a bit rudimentary, it should work.
Alternatively, you could use a table like this:
create table video_product (
id_association int not null auto_increment,
id_video int,
id_product int,
primary key (id_association)
);
The problem with this solution is that the PrestaShop ObjectModel core does not provide any method to automatically update or delete the related tables (at least as far as I know), so you have to insert the code to manage the "video_product" table in your "Video" class.
If you want an example of how to do this, you should look at the classes/Product.php script, which manages the product table and all its related tables (categories, tags, features, attachments, etc.).
To have an idea of how the Prestashop database is structured, have a look at the docs/dbmodel.mwb file, which contains the schema of the database; this file can be viewed by using the MySQL Workbench application.
I have a few different contact forms in my CakePHP 2.0 application. All of the contact forms are emailing as they should, but I need this particular one to also save the form results to the database. The post data is populating, and I can print_r() and pr() the form data. I can even email the post data. However, it is not actually saving the data to the model table. The database table is named contacts and has the following fields: id, publication, company, name, email, phone, message, contact_method, selections, received.
Here is my model:
class Contact extends AppModel {
public $name = 'Contact';
public $useTable = 'contacts';
public $validate = array(
'name' => array(
'rule' => 'notEmpty'
),
'email' => array(
'rule' => 'notEmpty'
)
);
Here is my controller:
App::uses('CakeEmail', 'Network/Email');
class ContactsController extends AppController
{
public $name = 'Contacts';
public $helpers = array('Html', 'Form', 'Js');
public $components = array('Email', 'Session');
...
public function contact_att() {
if ($this->request->is('post')) {
//pr($this->data);
if ($this->Contact->save($this->request->data)) {
$this->redirect('/pages/publications-alabama-turf-times');
$this->Session->setFlash("Mesage Saved!");
}
else {
print_r($this->data);
Configure::write('debug', 2);
debug($this->Contact->validationErrors);
exit;
}
}
Here is the form in my view:
echo $this->Form->create('Contact', array(
'action' => 'contact_att',
'label' => '',
'class' => 'pubs'));
echo $this->Form->input('publication', array(
'type' => 'hidden',
'value' => 'A',
'label' => ''));
echo $this->Form->input('company', array(
'default' => 'company name (required)',
'onfocus' => 'clearDefault(this)',
'label' => array(
'text' => 'Company Name',
'style' => 'position:absolute;')));
echo $this->Form->input('name', array(
'default' => 'name (required)',
'onfocus' => 'clearDefault(this)',
'label' => array(
'text' => 'Your Name',
'style' => 'position:absolute;')));
echo $this->Form->input('phone', array(
'default' => 'phone number (required)',
'onfocus' => 'clearDefault(this)',
'label' => array(
'text' => 'Your Phone Number',
'style' => 'position:absolute;')));
echo $this->Form->input('email', array(
'default' => 'email (required)',
'onfocus' => 'clearDefault(this)',
'label' => array(
'text' => 'Your Email Address',
'style' => 'position:absolute;')));
echo $this->Form->input('message', array(
'label' => array(
'text' => 'Your Message',
'style' => 'position:absolute;')));
echo $this->Form->input('contact_method', array(
'type' => 'radio',
'style' => 'padding-right:20px;',
'legend' => 'Preferred contact method:',
'options' => array(
'phone' => 'phone',
'email' => 'email'
)
));
echo $this->Form->input('selections', array(
'type' => 'select',
'label' => array(
'text' => 'I am interested in the following:',
'style' => 'display:block; width:250px; margin-left:-12px;padding-bottom:15px;'),
'multiple' => 'checkbox',
'options' => array(
'ABC' => 'ABC',
'DEF' => 'DEF',
'GHI' => 'GHI'
)
));
echo $this->Form->end('Submit');
What am I missing?
After much banging my head on the desk, the answer turned out to be simple -- of course. I simply removed this line from my model. I thought that having it set to the correct table would be fine, but turns out, it needed to be removed:
public $useTable = 'contacts';
You can try with this:
$this->Contact->save($this->request->data, false);
Try with:
debug($this->model->invalidFields());
sometimes, model have errors on validations, and not shows with validationErrors()
also note this..
If $fieldList is not supplied, a malicious user can add additional fields to the form data (if you are not using SecurityComponent), and by this change fields that were not originally intended to be changed.
http://book.cakephp.org/2.0/en/models/saving-your-data.html
take some time and read this documentation is very important, I hope have helped you.
Friend, I see your problem, check..
This line is missing in your controller
public $uses = array('Contact');
put and try, then you told me...
Is post will only return true when the form sets the posted hidden flag. So try this instead.
if(!empty($this->request->data))
Pls add this line
$this->Contact->create();
before you tried to save using
if ($this->Contact->save($this->request->data)) {