Scenario ¶
I'm developing a website that has an option to look up a car's registration number via SOAP and return additional details such as make, model, colour etc.
This should in turn update the fields for make, model, colour etc on the Vehicle form. It also checks to see that the details returned by SOAP are in the database and create them if not.
I'm by no means an expert in yii, I installed it a couple of weeks ago. This was a bit of a stumbling block for me and took me a few days to figure out. So thought I would share the code and hope it saves yii newbies a bit of time.
Acknowledgements ¶
Zaccaria for pointing me in the right direction.
Data structure ¶
CREATE TABLE IF NOT EXISTS `dms_vehicle` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`registration_number` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`chassis_number` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`vehicle_make_id` int(11) DEFAULT NULL,
`vehicle_model_id` int(11) DEFAULT NULL,
`vehicle_colour_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_vehicle_vehicle_make` (`vehicle_make_id`),
KEY `FK_vehicle_vehicle_model` (`vehicle_model_id`),
KEY `FK_vehicle_vehicle_colour` (`vehicle_colour_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `dms_vehicle_colour` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dvla_code` varchar(1) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `dvla_code` (`dvla_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `dms_vehicle_make` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dvla_code` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `dvla_code` (`dvla_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1 ;
CREATE TABLE IF NOT EXISTS `dms_vehicle_model` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`dvla_code` varchar(5) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`vehicle_make_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
UNIQUE KEY `dvla_code` (`dvla_code`),
KEY `FK_vehicle_model_vehicle_make` (`vehicle_make_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=17 ;
ALTER TABLE `dms_vehicle`
ADD CONSTRAINT `FK_vehicle_vehicle_colour` FOREIGN KEY (`vehicle_colour_id`) REFERENCES `dms_vehicle_colour` (`id`),
ADD CONSTRAINT `FK_vehicle_vehicle_make` FOREIGN KEY (`vehicle_make_id`) REFERENCES `dms_vehicle_make` (`id`),
ADD CONSTRAINT `FK_vehicle_vehicle_model` FOREIGN KEY (`vehicle_model_id`) REFERENCES `dms_vehicle_model` (`id`),
ALTER TABLE `dms_vehicle_model`
ADD CONSTRAINT `FK_vehicle_model_vehicle_make` FOREIGN KEY (`vehicle_make_id`) REFERENCES `dms_vehicle_make` (`id`);
Vehicle Controller ¶
Create the models and CRUD using gii, then edit VehicleController.php
Access rules ¶
My action is called hpicheck, so add this to the access rules
public function accessRules() {
return array(
array('allow', // only registered users can view and update
'actions' => array('index', 'view', 'admin','create', 'update', 'hpicheck' ),
'users' => array('@'),
),
array('allow', // Only admins can delete
'actions' => array('delete'),
'expression' => 'Yii::app()->getModule(\'user\')->isAdmin()',
),
array('deny', // deny all users - default action
'users' => array('*'),
),
);
}
SOAP/AJAX function ¶
Then create the hpicheck function in the vehicle controller
public function actionHpiCheck() {
if (Yii::app()->request->isAjaxRequest) {
// get the parameter passed via ajax from the _form.php
$registration_number = Yii::app()->request->getParam('registration_number');
if ($registration_number == '')
{
// No registration number has been entered so send the error back to the form
echo CJSON::encode(array(
'error' => 'true',
'status' => 'HPI check failed, please enter a registration number '
));
// exit;
Yii::app()->end();
}
else
{
// Create the options for SOAP
$options = array(
'soap_version' => SOAP_1_2,
'exceptions' => true,
'trace' => 1,
);
// Create the parameters to be passed to the enquire() function
$params->Request->Asset->Vrm = $registration_number;
// url for the soap service
$url = 'http://soapurl.com';
try {
// Open a soap client
$soapClient = new SoapClient($url, $options);
// call the soap service's function with the parameters
// returns an object with additional vehicle details
$hpi = $soapClient->enquire($params);
// the enquire() function is provided by the vehicle checking company - it isn't a soap function.
// To get a list of available functions, use var_dump($soapClient->__getFunctions());
// Set the status to blank, this is for recording any errors
$status = '';
// Get the make code and description from the $hpi object
$makeCode = $hpi->RequestResults->Asset->PrimaryAssetData->DVLA->Make->Code;
$makeDescription = $hpi->RequestResults->Asset->PrimaryAssetData->DVLA->Make->Description;
// Create blank variables just in case...
$makeOption = '';
$make_id=0;
// Have a look to see if the makeCode exists in the VehicleMake table
$make = VehicleMake::model()->find('dvla_code=:dvla_code', array(':dvla_code' => $makeCode));
if ($make == null) {
// It doesn't exist so create it
try
{
$make = new VehicleMake;
$make->dvla_code = $makeCode;
$make->name = $makeDescription;
$make->save();
$make_id = $make->id;
$makeOption = CHtml::tag('option', array('value' => $make_id),
CHtml::encode($makeDescription), true);
}
catch (Exception $e)
{
// This will catch any database errors, duplicates for example
Yii::log($e->getMessage());
$status .= $e->getMessage() . '<br/>';
// Send the error back to the form
echo CJSON::encode(array(
'error' => 'true',
'status' => $status,
));
// exit;
Yii::app()->end();
}
}
else
{
// We have found the make, so get the id
$make_id = $make->id;
}
// repeat the above code for VehicleModel and VehicleColour
// At some stage I'll create a generic function
...
if ($status=='')
{
// blank status so all is well
$status = 'HPI check complete';
}
// Pass our data back to the _form.php via json
echo CJSON::encode(array(
'error' => 'false',
'status' => $status,
'colour_id' => $colour_id,
'colourOption' => $colourOption,
'make_id' => $make_id,
'makeOption' => $makeOption,
'model_id' => $model_id,
'modelOption' => $modelOption,
));
// exit;
Yii::app()->end();
}
catch (SoapFault $soapFault)
{
// Theres a problem with SOAP
// or the enquire() function threw an error, an invalid registration number for example
$status = 'HPI Error : ' . substr($soapFault->faultcode, strlen('soapenv:'));
$status .= ' (' . $soapFault->detail->HpiSoapFault->Error->Code . ') ';
$status .= $soapFault->detail->HpiSoapFault->Error->Description . '<br/>';
echo CJSON::encode(array(
'error' => 'true',
'status' => $status,
));
// exit;
Yii::app()->end();
}
}
}
}
Vehicle Form ¶
Finally we need modify the vehicle view _form.php to send and receive the data
<div class="row">
<?php echo $form->labelEx($model,'registration_number'); ?>
<?php echo $form->textField($model,'registration_number',array('size'=>8,'maxlength'=>8)); ?>
<?php echo $form->error($model,'registration_number'); ?>
</div>
<?php echo CHtml::button('HPI Check', array( 'onclick'=>"{hpiCheck();}" ) ); ?>
<div id='hpistatus'></div>
<div class="row">
<?php echo $form->labelEx($model,'vehicle_make_id'); ?>
<?php echo $form->dropDownList($model,'vehicle_make_id', CHtml::listData(VehicleMake::model()->findAll(), 'id', 'name')); ?>
<?php echo $form->error($model,'vehicle_make_id'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'vehicle_model_id'); ?>
<?php echo $form->dropDownList($model,'vehicle_model_id', CHtml::listData(VehicleModel::model()->findAll(), 'id', 'name')); ?>
<?php echo $form->error($model,'vehicle_model_id'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'vehicle_colour_id'); ?>
<?php echo $form->dropDownList($model,'vehicle_colour_id', CHtml::listData(VehicleColour::model()->findAll(), 'id', 'name')); ?>
<?php echo $form->error($model,'vehicle_colour_id'); ?>
</div>
<script type="text/javascript">
// The bits above should be familiar to you
// This function is called by the "HPI check" button above
function hpiCheck()
{
<?php echo CHtml::ajax(array(
// the controller/function to call
'url'=>CController::createUrl('vehicle/hpiCheck'),
// Data to be passed to the ajax function
// Note that the ' should be escaped with \
// The field id should be prefixed with the model name eg Vehicle_field_name
'data'=>array('registration_number'=>'js:$(\'#Vehicle_registration_number\').val()',
// To pass multiple fields, just repeat eg:
// 'chassis_number'=>'js:$(\'#Vehicle_chassis_number\').val()',
),
'type'=>'post',
'dataType'=>'json',
'success'=>"function(data)
{
// data will contain the json data passed by the hpicheck action in the controller
// Update the status
$('#hpistatus').html(data.status);
if (data.error=='false')
{
// If there are no errors then update the fields
// As mentioned above, the id is prefixed by the model name eg Vehicle_field_name
// If its a new record, then add it to the select options first
if (data.colourOption!='') $('#Vehicle_vehicle_colour_id').append(data.colourOption);
// Then change the selected option
$('#Vehicle_vehicle_colour_id').val(data.colour_id);
if (data.makeOption!='') $('#Vehicle_vehicle_make_id').append(data.makeOption);
$('#Vehicle_vehicle_make_id').val(data.make_id);
if (data.modelOption!='') $('#Vehicle_vehicle_model_id').append(data.modelOption);
$('#Vehicle_vehicle_model_id').val(data.model_id);
}
} ",
))?>;
return false;
}
</script>
hi, why your jquery code is in this style manner?
did not you write jquery code like below?
var baseUrl = "http://www.example.com/";
$(function(){
...
jQuery.ajax({
data: {key: value, ...}, url: base_url + 'vehicle/hpiCheck', type: 'POST', dataType: 'json', success:function(suc){}, error: function(err){}
});
})
Where and how did you learn to use Ajax and Json?
Thanks a lot for sharing! But my current level knowledge of Ajax and Json is just know their definition, and I just went through Yii official guide and screen cast. Can you point the most basic materials about Ajax in Yii?
Thank you!
Thanks much
You have really saved me a lot. Am doing something of the sort. And a really thank for this.
id
You can avoid to hardcode all the id in this manner:
Instead of
"$('#Vehicle_vehicle_colour_id')"
Use:
"$('#".CHtml::activeId($model, 'vehicle_colour_id' )."')"
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.