Submitting the data only reloads the page, no errors or messages is given by CakePHP.
The code follows the same/similar structure as the blog tutorial.
The view code
<?php
echo $this->Form->create('Sm');
echo $this->Form->input('recievers', array('rows' => '1'));
echo $this->Form->input('subject');
echo $this->Form->input('message');
echo $this->Form->end('SEND');
?>
Controller code
public function send() {
if ($this->request->is('sm')) {
$this->Sm->create();
if ($this->Sm->save($this->request->data)) {
$this->Session->setFlash('Sms has been added to the database');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Unable to send sms.');
}
}
}
Model code
class Sm extends AppModel {
public $validate = array(
'subject' => array(
'rule' => 'notEmpty'
),
'message' => array(
'rule' => 'notEmpty'
),
'recievers' => array(
'rule' => 'notEmpty'
)
); }
Exported SQL
CREATE TABLE IF NOT EXISTS `sms` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`subject` varchar(150) DEFAULT NULL,
`message` text,
`sender` varchar(50) DEFAULT NULL,
`recievers` text,
`sent` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;
You've specified an incorrect request 'method';
if ($this->request->is('sm')) {
Should be:
if ($this->request->is('post')) {
I suspect you got confused by the examples on CakePHP, which use a 'post' Model. However this line is to check the type of request used to access the page, e.g. post, get, put.
By checking for the right request method, CakePHP will only insert/update the data is the form is sent/submitted, otherwise the form is just shown without updating the database
You forget to define name property inside model.
var $name = 'Sm';
Just a few minutes ago, I was facing same type of problem. My problem was more weird. In my controller I used something like this:
if( $this->MyModel->save( $this->request->data ) ) {
//positive. proceed.....
}
else {
//negative. show error
pr( $this->MyModel->validationErrors );
}
As you can see I've handled the negative case but still I could see nothing. Even in my model, I used beforeSave and afterSave to check. In my beforeSave model, I could see a perfectly formatted array ready to be saved but I afterSave was not triggering which means the data was not saved. Hence I should see error from my controller. Still no solution.
Now this is how I figured out the problem. I checked the table the data is gonna be saved into. The table had lots of columns with NOT NULL attribute. The data I was saving had some fields with NULL values. So theoretically, I should see validationErrors in the controller as a reason but unfortunately it was not showing. Setting those fields nullable solved my problem. So my suggestion to you is to check which fields might have NULL value and set those nullable and make sure the NOT NULL fields have some values.
Hope this helps. Cheers!!!
Related
The app I'm working on (an order form) allows the user to enter multiple sub-records within an iframe. These sub-records are joined to the main record via a foreign key.
main_records line_items
----------- ----------
id int(11) PK etc. id int(11) PK etc.
main_record_id (FK)
I need the app to check whether at least one line item exists within this iframe before form submission. I would like to take advantage of the $validate functionality within the model, but I'm unsure how to proceed. Here's what I've tried in the Main model:
App::uses('AppModel', 'Model', 'LineItem');
public $hasMany = array(
'LineItem' => array(
'className' => 'LineItem',
'foreignKey' => 'main_record_id',
'dependent' => false
)
);
public $validate = array(
'main_record_id' = array(
'allowEmpty' => false,
'rule' => 'checkForLineItem',
'message' => 'You must enter at least one line item!'
)
);
//Check to make sure there is at least one line item before saving changes/submitting for approval
function checkForLineItem($id) {
$lines = $this->LineItem->find('all', array(
'fields' => array('LineItem.main_record_id'),
'conditions' => array('LineItem.main_record_id'=>$id, 'LineItem.deleted_record'=>0))
);
if(!empty($lines)) {
return true;
} else {
return false;
}
}
I also track whether the line item has been deleted. If it has, then it is not added to $lines.
I know I can accomplish this in the Controller, but as far as I know, that would require the form to post, and the user would lose any changes upon postback (I haven't yet implemented jQuery on this form). Am I on the right track with how to do this? What changes should I make to get this to work?
Your code looks about right, but validation indeed happens in form submit. If you want to check it prior to that you have to do in JavaScript (jquery). E.g. create a controller action that return if there are existing line items for given main record id and call it via AJAX.
I have a table called a_forms, and I'm trying to create a drop down menu on a page of AForms that has a list of all the rows of a_forms. I want each choice in the drop down to link directly to the view of that form. Here is my forms table:
fid int(3) unsigned auto_increment (primary key)
title varchar(100)
created timestamp CURRENT_TIMESTAMP on update
modified timestamp
I was able to get as far populating the drop down menu, however I'm having trouble with the second part - linking each choice with the view selected. I'm a beginner to CakePHP so I am probably missing something. Here is the function in AFormsController:
public function forms($id = null)
{
$query = $this->AssessmentForms->find('all');
$result = $query->toArray();
$assessmentForm = $this->AssessmentForms->get($id, [ 'contain' => [] ]);
$this->set('assessmentForm', $assessmentForm);
$this->set('_serialize', ['assessmentForm']);
$data = $this->AssessmentForms->find('list', array('fields' => array('fid', 'title')));
$this->set('forms', $data);
}
forms.ctp:
<?php $this->Form->input('aform.select one', ['type' => 'select', 'options' => $forms, 'empty' => 'Choose One', 'onchange' => 'this.form.submit();']);?>
That gives me "Record not found in table "a_forms" with primary key [NULL]"
I also tried:
<?php $this->Form->create('Forms', array( 'url' => ['controller'=>'a_forms', 'action'=>'view', $aForm->fid])); ?>
And added this to the controller:
$aForms = $this->AForms->find('list');
It doesn't throw an error but I get a "Undefined variable: aForms [APP/Template/AForms/forms.ctp, line 10" in the view
I saw other people struggling with the 'onchange' method so I'm not sure if that's the right approach. I'm using version 3.1.0. Let me know if you need any more information!
Still don't quite know how to appropriately create queries with find(), but I found a way around with:
<ul class="dropdown-menu">
<?php foreach ($aForms as $aForm): ?>
<li> <?= $this->Html->link($aForm->title, ['action' => 'fill', $aForm->fid]) ?></li>
<?php endforeach; ?>
</ul>
And this in the controller:
$this->set('assessmentForms', $this->paginate($this->AssessmentForms));
$this->set('_serialize', ['assessmentForms']);
I pulled that directly from the bake-generated index() function. If anyone has a more syntactically non-hackish way of solving this, please let me know!
My debug value is set to 2 and I think because there's no data being passed here I'm getting a validation error, which is why this was first appearing to be a phantom error. I'm not sure though as I'm still new to Cakephp.
I have an Addresses controller that is passing data to my model that looks like so:
public function add() {
if ($this->request->is('post')) {
$this->Address->create();
if ($this->Address->save($this->request->data)) {
$this->Session->setFlash(__('The address has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The address could not be saved. Please, try again.'));
}
}
$users = $this->Address->User->find('list');
$this->set(compact('users'));
}
However when I debug using die(debug($this->request->data)))) I get the following result, revealing that there is nothing being passed in my id field:
/app/Controller/AddressesController.php (line 61)
array(
'Address' => array(
'id' => '',
'building_number' => '1',
'street_name' => 'Test Street',
'city' => 'Cityville',
'post_code' => 'N113AQ',
'user_id' => '1'
)
)
Any ideas as to why nothing is being passed into the id field? I have controllers working in exactly the same way for different tables that go off perfectly fine.
My Address.id field in my database is set to auto increment and is named correctly, $this->Address->save() returns false too.
If $this->request->data contains an array element named after the form’s model, and that array contains a empty value of the model’s primary key(here the id), then the FormHelper will create an add form for that record. For add method HTTP POST verb is ok. POST is for create and PUT is for edit in CakePHP. You can check validations and change the request type to non-GET. It may work.
if (!$this->request->is('get')){
//Save logic here
}
I am having a problem with the form select helper. On my page I have two forms.
One is a quick search form. This one uses state_id.
Upon searching in URL: state_id:CO
This will auto select the correct value in the drop down.
However, when I search with the advanced form. The Field is trail_state_id and
in URL: trail_state_id:CO
For some reason it will not default it to the correct value. It just resets the form to no selections. The values are searhed properly, just the form helper is not recognizing that a field with the same name in the url is set. Any thoughts?
<?php
class Trail extends AppModel {
public $filterArgs = array(
array('name' => 'state_id','field'=>'Area.state_id', 'type' => 'value'),
array('name'=>'trail_state_id','field'=>'Area.state_id','type'=> 'value'),
);
}
?>
in URL: trail_state_id:CO
<?php
echo '<h4>State*:</h4><div>'.$this->Form->select('trail_state_id', $stateSelectList, null, array('style'=>'width:200px;','escape' => false,'class'=> 'enhanced required','empty'=> false));
?>
Using the 3rd argument in the helper you can set a default. I did it the following way;
echo '<h4>State*:</h4><div>'.$this->Form->select('trail_state_id', $stateSelectList, (empty($this->params['named']['trail_state_id']) ? null: $this->params['named']['trail_state_id']), array('style'=>'width:200px;','escape' => false,'class'=> 'enhanced required','empty'=> false));
I have rewritten the app/code/core/Mage/Adminhtml/Block/Sales/Order/Grid.php
with app/code/local/Mage/Adminhtml/Block/Sales/Order/Grid.php
& have created a renderer to display customer's email column in grid.
Here is my renderer file:
class Mage_Adminhtml_Block_Renderer_Customer extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
{
public function render(Varien_Object $row)
{
$model = Mage::getModel('customer/customer')->load($row->getCustomerId());
return $model->getEmail();
}
}
& here is my Grid changes (I just added a column, & I intend to make it search-able)
$this->addColumn('billing_name', array(
'header' => Mage::helper('sales')->__('Bill to Name'),
'index' => 'billing_name',
));
// this is new col.
$this->addColumn('customer_email', array(
'header' => Mage::helper('sales')->__('Customer Email'),
'renderer' => 'adminhtml/renderer_customer',
));
I am getting what I want. But this col/ has a lot of whitespace both leading & trailing
due to this I think this col. is not search-able.
Can Anybody suggest what can be done in order to remove these white spaces
Many thanks in advance
EDIT
After few days I have figured out that these white spaces are common in the grid & it has nothing to do with the search-able option.
Can anybody suggest that how to make a custom column in search-able that has been added to a grid by using a renderer ???
Thanks
2 EDIT
Guys According to the clockworkgeek I have customized
my _prepareCollection() method of the overwritten grid as follows
protected function _prepareCollection()
{
// 'sales/order_collection' is changed from 'sales/order_grid_collection'
$collection = Mage::getResourceModel('sales/order_collection');
$collection->addAttributeToSelect('*')
->joinAttribute('billing_firstname', 'order_address/firstname', 'billing_address_id', null, 'left')
->joinAttribute('billing_lastname', 'order_address/lastname', 'billing_address_id', null, 'left')
->joinAttribute('shipping_firstname', 'order_address/firstname', 'shipping_address_id', null, 'left')
->joinAttribute('shipping_lastname', 'order_address/lastname', 'shipping_address_id', null, 'left')
->joinAttribute('billing_fax', 'order_address/fax', 'billing_address_id', null, 'left')
->joinAttribute('billing_telephone', 'order_address/telephone', 'billing_address_id', null, '')
->addExpressionAttributeToSelect('billing_name',
'CONCAT({{billing_firstname}}, " ", {{billing_lastname}})',
array('billing_firstname', 'billing_lastname'))
->addExpressionAttributeToSelect('shipping_name',
'CONCAT({{shipping_firstname}}, " ", {{shipping_lastname}})',
array('shipping_firstname', 'shipping_lastname'));
$this->setCollection($collection);
return parent::_prepareCollection();
}
I also have investigated that for Grid Magento obtains data from sales_flat_order_grid table not from sales_flat_order this is the reason it was reporting error of unknow column as per the clockworkgeek first solution
THe issue with current implementation is Magento reports an error Fatal error: Call to undefined method Mage_Sales_Model_Mysql4_Order_Collection::addExpressionAttributeToSelect()
as Mage_Sales_Model_Mysql4_Order_Collection does not have addExpressionAttributeToSelect method instead it has addExpressionFieldToSelect method
Now I need help to write a proper syntax for addExpressionAttributeToSelect method. Changing the method name only is not helping me. I also have referred the docs
Add 'index' => 'email' to your addColumn() in the Grid.php and then try something like this:
$emailaddress = trim($row->getData($this->getColumn()->getIndex()));
return ''.$emailaddress.'';
That way you strip the whitespace and also provide a clickable link for your admin users :)
In response to the second part of your question may I offer this little trick.
Adminhtml grid columns can take an extra filter_condition_callback parameter which takes a standard PHP callback type. In your case you might modify the grid like this:
protected function _prepareColumns() {
// ...
$this->addColumn('customer_email', array(
'header' => Mage::helper('sales')->__('Customer Email'),
'renderer' => 'adminhtml/renderer_customer',
'filter_condition_callback' => array($this, 'addCustomerEmailFilter'),
));
}
public function addCustomerEmailFilter(Mage_Eav_Model_Entity_Collection_Abstract $collection, Mage_Adminhtml_Block_Widget_Grid_Column $column) {
$collection->addAttributeToFilter('customer_email', $column->getFilter()->getValue());
}
But all that still feels a bit messy, especially if the attribute is not a first class column. For those unusual cases you can combine the output processing and searching in the collection class...
protected function _initSelect() {
parent::_initSelect();
// email is existing column, customer_email is generated column
$this->addExpressionAttributeToSelect(
'customer_email',
'TRIM({{email}})',
array('email')
);
return $this;
}
The addExpressionAttributeToSelect() method temporarily stores the SQL expression as a mapped field so that when a grid tries to search for customer_email it gets substituted by the expression instead.