Tag Archives: backbone

Yii and backbone js

I tried Backbone.js. Very nice js library BTW. It’s quite simple but at same time have nice functionality – all you need in order to make your frontend smarter. That’s why I like it. I’d call it jquery style he-he 🙂 – small but powerful.
As I remember Backbone js has grown from some rails project. So it has nice integration with rails.
But I tried to use it with yii. And I need to add some tricks in order to make it work.

So first of all backbone JS sends all info decoded by JSON. You can change data type. But this is way for dweebs (joking :). Unfortunatelly yii has some problems with JSON decoded data and REST. So let’s look what we have

public function getPost($name,$defaultValue=null)
{
return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
}

In our case POST data will be in “Request Payload” header i.e. we need to use getRawData function to fetch it (or getRestParams() inorder to fetch and parse data)
But look at getRestParams

if(function_exists('mb_parse_str')) {
    mb_parse_str($this->getRawBody(), $result);
} else {
    parse_str($this->getRawBody(), $result);
}

But in our case we have JSON data. I’ve added pull request (btw my first pull request to yii). Shortly we still talking on it. Not sure will it be approved or declined. But you can find it here https://github.com/yiisoft/yii/pull/2059 and here  Yii forum thread.
In the mean time here’s my custom HttpRequest component. They key is to check $_SERVER[‘CONTENT_TYPE’] and decode before parsing.


<?php

namespace Rz\components;

class HttpRequest extends \CHttpRequest
{

    protected $_restParams;

	/**
	 * Returns request parameters. Typically PUT or DELETE.
	 * @return array the request parameters
	 * @since 1.1.7
	 * @since 1.1.13 method became public
	 */
	public function getRestParams()
	{
		if($this->_restParams===null)
		{
			$result=array();
            if ($this->_isJsonEncoded()) {
                $result = \CJSON::decode($this->getRawBody());
            } else {
                if(function_exists('mb_parse_str')) {
                    mb_parse_str($this->getRawBody(), $result);
                } else {
                    parse_str($this->getRawBody(), $result);
                }
            }

			$this->_restParams=$result;
		}

		return $this->_restParams;
	}


    /**
	 * Returns the named POST parameter value.
	 * If the POST parameter does not exist, the second parameter to this method will be returned.
	 * @param string $name the POST parameter name
	 * @param mixed $defaultValue the default parameter value if the POST parameter does not exist.
	 * @return mixed the POST parameter value
	 * @see getParam
	 * @see getQuery
	 */
	public function getPost($name,$defaultValue=null)
	{
        if ($this->_isJsonEncoded()) {
            $data = \CJSON::decode($this->getRawBody());
            return isset($data[$name]) ? $data[$name] : $defaultValue;
        } else {
            return isset($_POST[$name]) ? $_POST[$name] : $defaultValue;
        }
	}

    /**
	 * Returns the named DELETE parameter value.
	 * If the DELETE parameter does not exist or if the current request is not a DELETE request,
	 * the second parameter to this method will be returned.
	 * If the DELETE request was tunneled through POST via _method parameter, the POST parameter
	 * will be returned instead (available since version 1.1.11).
	 * @param string $name the DELETE parameter name
	 * @param mixed $defaultValue the default parameter value if the DELETE parameter does not exist.
	 * @return mixed the DELETE parameter value
	 * @since 1.1.7
	 */
	public function getDelete($name,$defaultValue=null)
	{
		if($this->getIsDeleteViaPostRequest())
			return $this->getPost($name, $defaultValue);

		if($this->getIsDeleteRequest())
		{
			$this->getRestParams();
			return isset($this->_restParams[$name]) ? $this->_restParams[$name] : $defaultValue;
		}
		else
			return $defaultValue;
	}

	/**
	 * Returns the named PUT parameter value.
	 * If the PUT parameter does not exist or if the current request is not a PUT request,
	 * the second parameter to this method will be returned.
	 * If the PUT request was tunneled through POST via _method parameter, the POST parameter
	 * will be returned instead (available since version 1.1.11).
	 * @param string $name the PUT parameter name
	 * @param mixed $defaultValue the default parameter value if the PUT parameter does not exist.
	 * @return mixed the PUT parameter value
	 * @since 1.1.7
	 */
	public function getPut($name,$defaultValue=null)
	{
		if($this->getIsPutViaPostRequest())
			return $this->getPost($name, $defaultValue);

		if($this->getIsPutRequest())
		{
			$this->getRestParams();
			return isset($this->_restParams[$name]) ? $this->_restParams[$name] : $defaultValue;
		}
		else
			return $defaultValue;
	}

    /**
     * Check is request encoded in JSON
     * @return bool
     */
    protected function _isJsonEncoded()
    {
        if (isset($_SERVER['CONTENT_TYPE']) && strpos($_SERVER['CONTENT_TYPE'], 'application/json') === 0) {
            return true;
        }
        return false;
    }
}

And one more note. If you want to use csrf verification perhaps you need to add such trick to your js

  $(document).ajaxSend(function(event, request, settings) {
    var data;
    if (settings.data) {
      data = jQuery.parseJSON(settings.data);
      data['YII_CSRF_TOKEN'] = $.cookie('YII_CSRF_TOKEN');
      settings.data = JSON.stringify(data);
    } else {
      settings.data = "YII_CSRF_TOKEN=" + encodeURIComponent($.cookie('YII_CSRF_TOKEN'));
    }
  });