I seem to be having an issue with my model->save() function being undefined.
For logistics purposes this is what I am creating.
I have an order form which displays a list of custom options & subsequent prices. There is a list at the top which is a base product which has to be chosen and options that either add a fixed price of $0-whatever or a percent calculated using the base price.
I wrote the scripts to do everything from format the output on the order form to do all the price calculations. Currently everything works except for when I go to save my model I get the error "Property "Order.save" is not defined."
I don’t quite understand what the issue is or where to even begin with fixing it, I am new to yii so, still learning a lot of the functionality.
I am still new to the passing data around part of Yii, I’ve only been working with it for a week or two. I can provide a sample of the generated html from all the forms if needed.
Any help is appreciated, I honestly don’t even know where to start looking.
OrderController.php
<?php
class OrderController extends GxController {
public function filters() {
return array(
'accessControl',
);
}
public function accessRules() {
return array(
array('allow',
'actions'=>array('index', 'view', 'Populateaddress'),
'users'=>array('@'),
),
array('allow',
'actions'=>array('minicreate', 'create', 'update', 'admin', 'delete'),
'users'=>array('admin'),
),
array('deny',
'users'=>array('*'),
),
);
}
public function actionView($id) {
$this->render('view', array(
'model' => $this->loadModel($id, 'Order'),
));
}
public function actionCreate() {
$model = new Order;
$this->performAjaxValidation($model, 'order-form');
if (isset($_POST['Order'])) {
$model->setAttributes($_POST['Order']);
if (!isset($POST['basePrice'])) {
//ERROR ERROR ERROR
}
else {
$model->setBasePriceID($_POST['basePrice']);
}
if (!isset($POST['childOptions'])) {
//ERROR ERROR ERROR
}
else {
$model->setChosenOptions($_POST['childOptions']);
}
if(!$model->save){
$msg = print_r($model->getErrors(),1);
throw CHttpException(400,'data not saving: '.$msg );
}
if ($model->save(false)) {
if (Yii::app()->getRequest()->getIsAjaxRequest())
Yii::app()->end();
else
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('create', array( 'model' => $model));
}
public function actionUpdate($id) {
$model = $this->loadModel($id, 'Order');
$this->performAjaxValidation($model, 'order-form');
if (isset($_POST['Order'])) {
$model->setAttributes($_POST['Order']);
if ($model->save()) {
$this->redirect(array('view', 'id' => $model->id));
}
}
$this->render('update', array(
'model' => $model,
));
}
public function actionDelete($id) {
if (Yii::app()->getRequest()->getIsPostRequest()) {
$this->loadModel($id, 'Order')->delete();
if (!Yii::app()->getRequest()->getIsAjaxRequest())
$this->redirect(array('admin'));
} else
throw new CHttpException(400, Yii::t('app', 'Your request is invalid.'));
}
public function actionIndex() {
$dataProvider = new CActiveDataProvider('Order');
$this->render('index', array(
'dataProvider' => $dataProvider,
));
}
public function actionAdmin() {
$model = new Order('search');
$model->unsetAttributes();
if (isset($_GET['Order']))
$model->setAttributes($_GET['Order']);
$this->render('admin', array(
'model' => $model,
));
}
public function actionPopulateaddress()
{
$cID = (int) $_POST['customer_id'];
$bData = Address::model()->findAll('customer_id=:customer_id AND type <= 1', array(':customer_id'=>$cID));
$bData = CHtml::listData($bData,'id','linkInfo');
$bDropdown = "<option value=''>Select Billing Address</option>";
foreach($bData as $value=>$name)
$bDropdown .= CHtml::tag('option', array('value'=>$value),CHtml::encode($name),true);
$dData = Address::model()->findAll('customer_id=:customer_id AND type = 2', array(':customer_id'=>$cID));
$dData = CHtml::listData($dData,'id','linkInfo');
$dDropdown = "<option value=''>Select Delivery Address</option>";
foreach($dData as $value=>$name)
$dDropdown .= CHtml::tag('option', array('value'=>$value),CHtml::encode($name),true);
// return data (JSON formatted)
echo CJSON::encode(array(
'billingA'=>$bDropdown,
'deliveryA'=>$dDropdown
));
}
}
Order.php (model)
<?php
Yii::import('application.models._base.BaseOrder');
class Order extends BaseOrder
{
private $_basePrice;
public $cOptions = array();
public $baseid;
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function setBasePriceID($basePriceID)
{
$this->_basePrice = Order::model()->findbyPk($basePriceID);
$this->baseid = $basePriceID;
}
public function setChosenOptions($chosenOptions = array())
{
$this->cOptions = $chosenOptions;
}
public function candaOptionPrice($optionID)
{
$optionRow = Options::model()->findbyPK($optionID);
if ($optionRow->price == 0.00) { }
else
{
if ($optionRow->price_type == 2) { $this->price += $optionRow->price; }
else {
$this->price += ($optionRow->price / 100) * $this->_basePrice;
}
}
}
public function beforeSave()
{ // Should have a base price & chosen options by now.
parent::beforeSave();
$this->price = $this->_basePrice;
if (is_array($this->cOptions)) {
foreach ($this->cOptions as $options)
{
$this->candaOptionPrice($options->id);
if ($options == end($this->chosenoptions))
{
$this->chosenoptions .= $options->id;
}
else {
$this->chosenoptions .= $options->id . ":";
}
}
}
else { $this->candaOptionPrice($this->cOptions); }
$this->balance = $this->price;
if ($this->isNewRecord) { $this->creation_date = date(""); }
}
}
BaseOrder.php
<?php
/**
* This is the model base class for the table "order".
* DO NOT MODIFY THIS FILE! It is automatically generated by giix.
* If any changes are necessary, you must set or override the required
* property or method in class "Order".
*
* Columns in table "order" available as properties of the model,
* followed by relations of table "order" available as properties of the model.
*
* @property integer $id
* @property integer $customer_id
* @property integer $billing_address_id
* @property string $delivery
* @property string $delivery_date
* @property integer $delivery_address_id
* @property string $creation_date
* @property string $price
* @property string $balance
* @property string $chosenoptions
* @property integer $baseid
*
* @property Address $billingAddress
* @property Address $deliveryAddress
* @property Customer $customer
* @property Payment[] $payments
*/
abstract class BaseOrder extends GxActiveRecord {
public static function model($className=__CLASS__) {
return parent::model($className);
}
public function tableName() {
return 'order';
}
public static function label($n = 1) {
return Yii::t('app', 'Order|Orders', $n);
}
public static function representingColumn() {
return 'delivery';
}
public function rules() {
return array(
array('customer_id, delivery', 'required'),
array('customer_id, billing_address_id, delivery_address_id, baseid', 'numerical', 'integerOnly'=>true),
array('delivery', 'length', 'max'=>1),
array('price, balance', 'length', 'max'=>10),
array('delivery_date, creation_date, chosenoptions', 'safe'),
array('billing_address_id, delivery_date, delivery_address_id, creation_date, price, balance, chosenoptions, baseid', 'default', 'setOnEmpty' => true, 'value' => null),
array('id, customer_id, billing_address_id, delivery, delivery_date, delivery_address_id, creation_date, price, balance, chosenoptions, baseid', 'safe', 'on'=>'search'),
);
}
public function relations() {
return array(
'billingAddress' => array(self::BELONGS_TO, 'Address', 'billing_address_id'),
'deliveryAddress' => array(self::BELONGS_TO, 'Address', 'delivery_address_id'),
'customer' => array(self::BELONGS_TO, 'Customer', 'customer_id'),
'payments' => array(self::HAS_MANY, 'Payment', 'order_id'),
);
}
public function pivotModels() {
return array(
);
}
public function attributeLabels() {
return array(
'id' => Yii::t('app', 'ID'),
'customer_id' => null,
'billing_address_id' => null,
'delivery' => Yii::t('app', 'Delivery'),
'delivery_date' => Yii::t('app', 'Delivery Date'),
'delivery_address_id' => null,
'creation_date' => Yii::t('app', 'Creation Date'),
'price' => Yii::t('app', 'Price'),
'balance' => Yii::t('app', 'Balance'),
'chosenoptions' => Yii::t('app', 'Chosenoptions'),
'baseid' => Yii::t('app', 'Baseid'),
'billingAddress' => null,
'deliveryAddress' => null,
'customer' => null,
'payments' => null,
);
}
public function search() {
$criteria = new CDbCriteria;
$criteria->compare('id', $this->id);
$criteria->compare('customer_id', $this->customer_id);
$criteria->compare('billing_address_id', $this->billing_address_id);
$criteria->compare('delivery', $this->delivery, true);
$criteria->compare('delivery_date', $this->delivery_date, true);
$criteria->compare('delivery_address_id', $this->delivery_address_id);
$criteria->compare('creation_date', $this->creation_date, true);
$criteria->compare('price', $this->price, true);
$criteria->compare('balance', $this->balance, true);
$criteria->compare('chosenoptions', $this->chosenoptions, true);
$criteria->compare('baseid', $this->baseid);
return new CActiveDataProvider($this, array(
'criteria' => $criteria,
));
}
}
Order _form view
<?php
/**
* Created by JetBrains PhpStorm.
* User: Jeffrey Mele
* Date: 5/7/13
* Time: 8:37 PM
* To change this template use File | Settings | File Templates.
*/
class orderForm {
private $_selectedOptions = array();
private $_model;
private $_output;
public function orderForm ($selectedOptions = array())
{
$this->_selectedOptions = $selectedOptions;
$this->start();
}
public function instantiateModel()
{
$this->_model = Catagory::model()->findAll();
}
private function start()
{
$this->instantiateModel();
$this->generateCategories($this->_model);
}
private function generateCategories($model)
{
foreach ($model as $catagoryRow)
{
$this->_output .= "<div class=\"row-fluid\"> <div class=\"span12\">
<h2>". $catagoryRow->name ."</h2>";
$this->generateOptions($catagoryRow->options);
$this->_output .= "</div></div>"; // Close Span 12 from up there
}
}
private function generateOptions($aOptions) // Generate options and subsequent labels
{
$spancount = 0; # have to create a new row every 4 items (span3 for each item)
$this->_output .= "<div class=\"row-fluid\"><div class=\"span12\"><div class=\"row-fluid\">";
foreach ($aOptions as $option)
{
$trimmedName = $option->name;
if ($option == end($aOptions)) { $spanvalue = 12 - $spancount; /* Last item of array */ } else { $spanvalue = 4; } /* not last item of array $str = str_replace(' ','',$str); */
if ($spancount == 12) { $this->_output .= "</div></div></div><div class=\"row-fluid\"><div class=\"span12\"><div class=\"row-fluid\">"; }
if ($option->price_type == 0) // If option is "Base price"
{
$this->_output .= "<div class=\"span{$spanvalue}\">
<label class=\"radio\" for=\"{$trimmedName}\">
<input type=\"radio\" name=\"baseChoice\" value=\"{$option->id}\" id=\"{$trimmedName}\"> $option->name < $option->price >
</label>
</div>";
}
else
{
$this->_output .= "<div class=\"span{$spanvalue}\">
<label class=\"checkbox\" for=\"{$trimmedName}\">
<input type=\"checkbox\" name=\"childOptions[]\" value=\"{$option->id}\" id=\"{$trimmedName}\"> $option->name < $option->price >
</label>
</div>";
}
if ($spancount == 12 ) { $spancount = 0; }
if($option == end($aOptions)) {$this->_output .= "</div></div></div>"; }
else { $spancount += 4; }
}
}
public function getOutput()
{
return $this->_output;
}
}
orderForm.php (called in view)
<?php
/**
* Created by JetBrains PhpStorm.
* User: Jeffrey Mele
* Date: 5/7/13
* Time: 8:37 PM
* To change this template use File | Settings | File Templates.
*/
class orderForm {
private $_selectedOptions = array();
private $_model;
private $_output;
public function orderForm ($selectedOptions = array())
{
$this->_selectedOptions = $selectedOptions;
$this->start();
}
public function instantiateModel()
{
$this->_model = Catagory::model()->findAll();
}
private function start()
{
$this->instantiateModel();
$this->generateCategories($this->_model);
}
private function generateCategories($model)
{
foreach ($model as $catagoryRow)
{
$this->_output .= "<div class=\"row-fluid\"> <div class=\"span12\">
<h2>". $catagoryRow->name ."</h2>";
$this->generateOptions($catagoryRow->options);
$this->_output .= "</div></div>"; // Close Span 12 from up there
}
}
private function generateOptions($aOptions) // Generate options and subsequent labels
{
$spancount = 0; # have to create a new row every 4 items (span3 for each item)
$this->_output .= "<div class=\"row-fluid\"><div class=\"span12\"><div class=\"row-fluid\">";
foreach ($aOptions as $option)
{
$trimmedName = $option->name;
if ($option == end($aOptions)) { $spanvalue = 12 - $spancount; /* Last item of array */ } else { $spanvalue = 4; } /* not last item of array $str = str_replace(' ','',$str); */
if ($spancount == 12) { $this->_output .= "</div></div></div><div class=\"row-fluid\"><div class=\"span12\"><div class=\"row-fluid\">"; }
if ($option->price_type == 0) // If option is "Base price"
{
$this->_output .= "<div class=\"span{$spanvalue}\">
<label class=\"radio\" for=\"{$trimmedName}\">
<input type=\"radio\" name=\"baseChoice\" value=\"{$option->id}\" id=\"{$trimmedName}\"> $option->name < $option->price >
</label>
</div>";
}
else
{
$this->_output .= "<div class=\"span{$spanvalue}\">
<label class=\"checkbox\" for=\"{$trimmedName}\">
<input type=\"checkbox\" name=\"childOptions[]\" value=\"{$option->id}\" id=\"{$trimmedName}\"> $option->name < $option->price >
</label>
</div>";
}
if ($spancount == 12 ) { $spancount = 0; }
if($option == end($aOptions)) {$this->_output .= "</div></div></div>"; }
else { $spancount += 4; }
}
}
public function getOutput()
{
return $this->_output;
}
}
Error
CException
Property "Order.save" is not defined.
C:\xampp\Yii_Core\framework\db\ar\CActiveRecord.php(143)
131 */
132 public function __get($name)
133 {
134 if(isset($this->_attributes[$name]))
135 return $this->_attributes[$name];
136 elseif(isset($this->getMetaData()->columns[$name]))
137 return null;
138 elseif(isset($this->_related[$name]))
139 return $this->_related[$name];
140 elseif(isset($this->getMetaData()->relations[$name]))
141 return $this->getRelated($name);
142 else
143 return parent::__get($name);
144 }
145
146 /**
147 * PHP setter magic method.
148 * This method is overridden so that AR attributes can be accessed like properties.
149 * @param string $name property name
150 * @param mixed $value property value
151 */
152 public function __set($name,$value)
153 {
154 if($this->setAttribute($name,$value)===false)
155 {
Stack Trace
#0
+ C:\xampp\Yii_Core\framework\db\ar\CActiveRecord.php(143): CComponent->__get("save")
#1
– C:\xampp\htdocs\test\protected\controllers\OrderController.php(55): CActiveRecord->__get("save")
50 }
51 else {
52 $model->setChosenOptions($_POST['childOptions']);
53 }
54
55 if(!$model->save){
56 $msg = print_r($model->getErrors(),1);
57 throw CHttpException(400,'data not saving: '.$msg );
58 }
59 if ($model->save(false)) {
60 if (Yii::app()->getRequest()->getIsAjaxRequest())
#2
+ C:\xampp\Yii_Core\framework\web\actions\CInlineAction.php(49): OrderController->actionCreate()
#3
+ C:\xampp\Yii_Core\framework\web\CController.php(308): CInlineAction->runWithParams(array("r" => "order/create"))
#4
+ C:\xampp\Yii_Core\framework\web\filters\CFilterChain.php(133): CController->runAction(CInlineAction)
#5
+ C:\xampp\Yii_Core\framework\web\filters\CFilter.php(40): CFilterChain->run()
#6
+ C:\xampp\Yii_Core\framework\web\CController.php(1145): CFilter->filter(CFilterChain)
#7
+ C:\xampp\Yii_Core\framework\web\filters\CInlineFilter.php(58): CController->filterAccessControl(CFilterChain)
#8
+ C:\xampp\Yii_Core\framework\web\filters\CFilterChain.php(130): CInlineFilter->filter(CFilterChain)
#9
+ C:\xampp\Yii_Core\framework\web\CController.php(291): CFilterChain->run()
#10
+ C:\xampp\Yii_Core\framework\web\CController.php(265): CController->runActionWithFilters(CInlineAction, array("accessControl"))
#11
+ C:\xampp\Yii_Core\framework\web\CWebApplication.php(282): CController->run("create")
#12
+ C:\xampp\Yii_Core\framework\web\CWebApplication.php(141): CWebApplication->runController("order/create")
#13
+ C:\xampp\Yii_Core\framework\base\CApplication.php(169): CWebApplication->processRequest()
#14
– C:\xampp\htdocs\test\index.php(13): CApplication->run()
08 defined('YII_DEBUG') or define('YII_DEBUG',true);
09 // specify how many levels of call stack should be shown in each log message
10 defined('YII_TRACE_LEVEL') or define('YII_TRACE_LEVEL',3);
11
12 require_once($yii);
13 Yii::createWebApplication($config)->run();
2013-05-08 07:08:54 Apache/2.2.17 (Win32) mod_ssl/2.2.17 OpenSSL/0.9.8o PHP/5.3.4 mod_perl/2.0.4 Perl/v5.10.1 Yii Framework/1.1.13