How To Adjust This Routes On Resfulyii Extension?

Hi there

We are quite new to Yii Framework and the reason we go this framework that we can utilise this webservice - from RESTFul API - http://www.yiiframework.com/extension/restfullyii/

We have this action defined on our controller:


public function actionListByCategory($id)

	{

		//$dataProvider=new CActiveDataProvider(ad::model()->with('subcategory'));

		//$this->render('index',array(

		//	'dataProvider'=>$dataProvider,

		//));

		

		$dataProvider=new CActiveDataProvider('ad',array(

                'criteria'=>array(

                    'order'=>'adid desc',

                    'condition'=>'subcatid = '.$id,

                ),

				'pagination'=>array(

                        'pageSize'=>10,

                        //'route'=>'user/login/login',

                ),

        ));

		$this->render('index',array(

			'dataProvider'=>$dataProvider,

		));

		

		

	}

But then how do execute this on the url on the browser with this /api/ - http://localhost:8888/dev-ph-com/webservice-dev-restful/index.php/ad/listbycategory/21

It doesnt’ seem to work and we have this message: {“success”:false,“message”:“Resource Not Found”,“data”:{“errorCode”:404,“message”:“Resource Not Found”}}

I believe this will be something in relation to routes maybe ?

Here’s the routes at Starship.Restfullyii extension - C:\wamp\www\dev-ph-com\webservice-dev-restful\protected\extensions\starship\RestfullYii\config


<?php

return [

	'api/<controller:\w+>'=>['<controller>/REST.GET', 'verb'=>'GET'],

	'api/<controller:\w+>/<id:\w*>'=>['<controller>/REST.GET', 'verb'=>'GET'],

	'api/<controller:\w+>/<id:\w*>/<param1:\w*>'=>['<controller>/REST.GET', 'verb'=>'GET'],

	'api/<controller:\w+>/<id:\w*>/<param1:\w*>/<param2:\w*>'=>['<controller>/REST.GET', 'verb'=>'GET'],


	['<controller>/REST.PUT', 'pattern'=>'api/<controller:\w+>/<id:\w*>', 'verb'=>'PUT'],

	['<controller>/REST.PUT', 'pattern'=>'api/<controller:\w+>/<id:\w*>/<param1:\w*>', 'verb'=>'PUT'],

	['<controller>/REST.PUT', 'pattern'=>'api/<controller:\w*>/<id:\w*>/<param1:\w*>/<param2:\w*>', 'verb'=>'PUT'],	


	['<controller>/REST.DELETE', 'pattern'=>'api/<controller:\w+>/<id:\w*>', 'verb'=>'DELETE'],

	['<controller>/REST.DELETE', 'pattern'=>'api/<controller:\w+>/<id:\w*>/<param1:\w*>', 'verb'=>'DELETE'],

	['<controller>/REST.DELETE', 'pattern'=>'api/<controller:\w+>/<id:\w*>/<param1:\w*>/<param2:\w*>', 'verb'=>'DELETE'],


	['<controller>/REST.POST', 'pattern'=>'api/<controller:\w+>', 'verb'=>'POST'],

	['<controller>/REST.POST', 'pattern'=>'api/<controller:\w+>/<id:\w+>', 'verb'=>'POST'],

	['<controller>/REST.POST', 'pattern'=>'api/<controller:\w+>/<id:\w*>/<param1:\w*>', 'verb'=>'POST'],

	['<controller>/REST.POST', 'pattern'=>'api/<controller:\w+>/<id:\w*>/<param1:\w*>/<param2:\w*>', 'verb'=>'POST'],


	'<controller:\w+>/<id:\d+>'=>'<controller>/view',

	'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',

	'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',

];

I’m appreciated your feedback.

UPDATED: Put the relevant external links

Hi,

You want to create the api module and set the url on main.php file

1) In API module go to the ApiContoller.php on comoponets folder and put the below code.


<?php

class ApiController extends GxController

{

	public $format = 'json';




	public function init()

	{

		parent::init();

		

		

	}

	public function getAPIDataStruct()

	{

		if (Yii::app()->request->getRequestType()=='GET') {

			$params = $_GET;

		}else if (Yii::app()->request->getRequestType()=='POST') {

			$params = $_POST;

		}else if (Yii::app()->request->getRequestType()=='REQUEST') {

			$params = $_REQUEST;

		}

		//$params = Yii::app()->request->getRequestType()=='GET';

		$params = '$_'.Yii::app()->request->getRequestType();

		$data = array(

		/*

			'request' => array(

			'method'=>  Yii::app()->request->getPathInfo(),

			//	'request_type'=>  '',

			'params' => $params

			),

			*/

			'response' => array('success'=>'', 'error'=>array())

		);

		return $data;

	}


	protected function _sendResponse($status = 200, $body = '', $content_type = 'text/xml')

	{

		$this->_checkAuth();

		// set the status

		$status_header = 'HTTP/1.1 ' . $status . ' ' . $this->_getStatusCodeMessage($status);

		header($status_header);

		// and the content type


		header('Content-type: ' . $content_type);





		// pages with body are easy

		if($body != '')

		{

			// send the body

			echo $body;

			exit;

		}

		// we need to create the body if none is passed

		else

		{

			// create some body messages

			$message = '';


			// this is purely optional, but makes the pages a little nicer to read

			// for your users.  Since you won't likely send a lot of different status codes,

			// this also shouldn't be too ponderous to maintain

			switch($status)

			{

				case 401:

					$message = 'You must be authorized to view this page.';

					break;

				case 404:

					$message = 'The requested URL ' . $_SERVER['REQUEST_URI'] . ' was not found.';

					break;

				case 500:

					$message = 'The server encountered an error processing your request.';

					break;

				case 501:

					$message = 'The requested method is not implemented.';

					break;

			}


			// servers don't always have a signature turned on

			// (this is an apache directive "ServerSignature On")

			$signature = ($_SERVER['SERVER_SIGNATURE'] == '') ? $_SERVER['SERVER_SOFTWARE'] . ' Server at ' . $_SERVER['SERVER_NAME'] . ' Port ' . $_SERVER['SERVER_PORT'] : $_SERVER['SERVER_SIGNATURE'];


			// this should be templated in a real-world solution

			$body = '

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

<html>

<head>

    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">

    <title>' . $status . ' ' . $this->_getStatusCodeMessage($status) . '</title>

</head>

<body>

    <h1>' . $this->_getStatusCodeMessage($status) . '</h1>

    <p>' . $message . '</p>

    <hr />

    <address>' . $signature . '</address>

</body>

</html>';


			echo $body;

			exit;

		}

	}


	protected function _getStatusCodeMessage($status)

	{


		$this->_checkAuth();

		// these could be stored in a .ini file and loaded

		// via parse_ini_file()... however, this will suffice

		// for an example

		$codes = Array(

		200 => 'OK',

		400 => 'Bad Request',

		401 => 'Unauthorized',

		402 => 'Payment Required',

		403 => 'Forbidden',

		404 => 'Not Found',

		500 => 'Internal Server Error',

		501 => 'Not Implemented',

		);


		return (isset($codes[$status])) ? $codes[$status] : '';

	}


	protected function _checkAuth()

	{

		return;

		// Check if we have the USERNAME and PASSWORD HTTP headers set?

		if(!(isset($_SERVER['HTTP_X_USERNAME']) and isset($_SERVER['HTTP_X_PASSWORD']))) {

			// Error: Unauthorized

			$this->_sendResponse(401);

		}

		$username = $_SERVER['HTTP_X_USERNAME'];

		$password = $_SERVER['HTTP_X_PASSWORD'];

		// Find the user

		$user=User::model()->find('LOWER(username)=?',array(strtolower($username)));

		if($user===null) {

			// Error: Unauthorized

			$this->_sendResponse(401, 'Error: User Name is invalid');

		} else if(!$user->validatePassword($password)) {

			// Error: Unauthorized

			$this->_sendResponse(401, 'Error: User Password is invalid');

		}

	}


	/**

	 * Converts an array to Xml

	 *

	 * @param mixed $arData The array to convert

	 * @param mixed $sRootNodeName The name of the root node in the returned Xml

	 * @param string $sXml The converted Xml

	 */

	public function arrayToXml( $arData, $sRootNodeName = 'data', $sXml = null , $nodeString = null)

	{

		//p($arData['response']['repairers_details'][0]['rep_address2']);

		// turn off compatibility mode as simple xml doesn't like it

		if ( 1 == ini_get( 'zend.ze1_compatibility_mode' ) )

		ini_set( 'zend.ze1_compatibility_mode', 0 );


		if ( null == $sXml )

		$sXml = simplexml_load_string( "<?xml version='1.0' encoding='utf-8'?><{$sRootNodeName} />" );


		// loop through the data passed in.

		foreach ( $arData as $_sKey => $_oValue )

		{

			//echo $_sKey ."<br/>";

			// no numeric keys in our xml please!

			if ( is_numeric($_sKey ) ) {

				//$_sKey = "node_". ( string )$_sKey;

				$_sKey = $nodeString. ( string )$_sKey;

			}

			//p($_sKey);


			// replace anything not alpha numeric

			if($_sKey != 'rep_address1' &&  $_sKey != 'rep_address2' )

			{

				$_sKey = preg_replace( '/[^a-z]/i', '', $_sKey );

			}

			// if there is another array found recrusively call this function


			if ( is_array( $_oValue ) )

			{


				$_oNode = $sXml->addChild( $_sKey );


				self::arrayToXml( $_oValue, $sRootNodeName, $_oNode,  $nodeString);

			}

			else

			{

				// add single node.

				$_oValue = htmlentities( $_oValue );

				$sXml->addChild( $_sKey, $_oValue );

			}

		}


		return( $sXml->asXML() );

	}


	/**

	 * Returns an Xml string representation of an array of CActiveRecords

	 *

	 * @param array $oRS

	 * @param array $arOptions

	 */


	public function xml2array($contents, $get_attributes=1, $priority = 'tag') {


		if(!$contents) return array();


		if(!function_exists('xml_parser_create')) {

			//print "'xml_parser_create()' function not found!";

			return array();

		}


		//Get the XML parser of PHP - PHP must have this module for the parser to work

		$parser = xml_parser_create('');


		xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); # http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss

		xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);

		xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);

		xml_parse_into_struct($parser, trim($contents), $xml_values);

		xml_parser_free($parser);


		if(!$xml_values) return;//Hmm...


		//Initializations

		$xml_array = array();

		$parents = array();

		$opened_tags = array();

		$arr = array();

		//print_r($arr);

		//exit;

		$current = &$xml_array; //Refference


		//Go through the tags.

		$repeated_tag_index = array();//Multiple tags with same name will be turned into an array

		foreach($xml_values as $data) {

			unset($attributes,$value);//Remove existing values, or there will be trouble


			//This command will extract these variables into the foreach scope

			// tag(string), type(string), level(int), attributes(array).

			extract($data);//We could use the array by itself, but this cooler.


			$result = array();

			$attributes_data = array();


			if(isset($value)) {

				if($priority == 'tag') $result = $value;

				else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode

			}


			//Set the attributes too.

			if(isset($attributes) and $get_attributes) {

				foreach($attributes as $attr => $val) {

					if($priority == 'tag') $attributes_data[$attr] = $val;

					else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'

				}

			}


			//See tag status and do the needed.

			if($type == "open") {//The starting of the tag '<tag>'

				$parent[$level-1] = &$current;

				if(!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag

					$current[$tag] = $result;

					if($attributes_data) $current[$tag. '_attr'] = $attributes_data;

					$repeated_tag_index[$tag.'_'.$level] = 1;


					$current = &$current[$tag];


				} else { //There was another element with the same tag name


					if(isset($current[$tag][0])) {//If there is a 0th element it is already an array

						$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;

						$repeated_tag_index[$tag.'_'.$level]++;

					} else {//This section will make the value an array if multiple tags with the same name appear together

						$current[$tag] = array($current[$tag],$result);//This will combine the existing item and the new item together to make an array

						$repeated_tag_index[$tag.'_'.$level] = 2;


						if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well

							$current[$tag]['0_attr'] = $current[$tag.'_attr'];

							unset($current[$tag.'_attr']);

						}


					}

					$last_item_index = $repeated_tag_index[$tag.'_'.$level]-1;

					$current = &$current[$tag][$last_item_index];

				}


			} elseif($type == "complete") { //Tags that ends in 1 line '<tag />'

				//See if the key is already taken.

				if(!isset($current[$tag])) { //New Key

					$current[$tag] = $result;

					$repeated_tag_index[$tag.'_'.$level] = 1;

					if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data;


				} else { //If taken, put all things inside a list(array)

					if(isset($current[$tag][0]) and is_array($current[$tag])) {//If it is already an array...


						// ...push the new element into that array.

						$current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result;


						if($priority == 'tag' and $get_attributes and $attributes_data) {

							$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;

						}

						$repeated_tag_index[$tag.'_'.$level]++;


					} else { //If it is not an array...

						$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value

						$repeated_tag_index[$tag.'_'.$level] = 1;

						if($priority == 'tag' and $get_attributes) {

							if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well


								$current[$tag]['0_attr'] = $current[$tag.'_attr'];

								unset($current[$tag.'_attr']);

							}


							if($attributes_data) {

								$current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data;

							}

						}

						$repeated_tag_index[$tag.'_'.$level]++; //0 and 1 index is already taken

					}

				}


			} elseif($type == 'close') { //End of tag '</tag>'

				$current = &$parent[$level-1];

			}

		}


		return($xml_array);

	}

}



2) Suppose i want to disaplay the get all city so i want to create the CityContrller on Api/Controller folder


<?php

class  CityController extends ApiController{


	/**

	 * @Method		  :	GetCityList

	 * @Params		  :

	 * @author        : Ankit Modi

	 * @created		  :	Aug 20 2012

	 * @Modified by	  :

	 * @modified	  :

	 * @Comment		  : This function will check the GetCityList.

	 */

	public function actionGetCityList($status = 200, $body = '', $content_type = 'text/json'){

		$status_header = 'HTTP/1.1 ' . $status . ' ';

		header($status_header);

		header('Content-type: ' . $content_type);

		$res = array();

		$error =array();

		$response=array();

		$post = file_get_contents("php://input");

		$model= new City();

		$response=$model->GetCityName();

		header('Content-type:application/json');

		echo CJSON::encode($response);

		exit();

	}

}

3) In my city model


public function GetCityName(){

		$model= new City();

		$city = $model->findAll('status=1');

		$city_arr = array();

		foreach($city as $data){

			$city_arr[] = array(

						'city_id'=>$data->id,

						'city_name'=>$data->city_name,

					);

		}

		if(!$city){

			$response['error']="0";

			$response['cityname']= 'Not found in DB';

		}else{

			$response['success']="1";

			$response['data']= $city_arr;

		}

		return $response;

	}




4)Finally you want to inatall the RestApi extesion add on firefox.

And type the URL on Request header


localhost/test/api/CityController/GetCityList

And pass the reuest header in json formet

like


{"id:","1","city_name:","test"} 

and see the output on respanse body on json formet.

I hope it’s some help.

Thanks Ankit for your solution.

However, I prefer to get it working for the Restful extension first and if it’s not I will jump in to your solution.