evan108108 / RESTFullYii

RESTFull API for your Yii application

Home Page:http://evan108108.github.com/RESTFullYii/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Sort using related properties

jcvalerio opened this issue · comments

Hi !

For example I have to entities
Races and Distance

A race have one distance.

So, when I request races order by distance.Quantity (integer number that represent for instance 10 miles) and StartingDate(date on race entity), I expect as a result:

  • races order first by distance.Quantity
  • then order by StartingDate

This is the request uri

http://server/api/race/?sort=[{"property":"distance.Quantity","direction":"ASC"},{"property":"StartingDate","direction":"ASC"}]

We are getting this query as a result

SELECT `t`.`RaceId` AS `t0_c0`,
       `t`.`DistanceId` AS `t0_c3`,
       `t`.`StartingDate` AS `t0_c4`,
       `t`.`StartingTime` AS `t0_c5`,
       `distance`.`DistanceId` AS `t2_c0`,
       `distance`.`Name` AS `t2_c1`,
       `distance`.`Quantity` AS `t2_c3`
FROM `Race` `t`
LEFT OUTER JOIN `Distance` `distance` ON (`t`.`DistanceId`=`distance`.`DistanceId`)
ORDER BY t.StartingDate ASC LIMIT 100

As you can see, distance.Quantity was not added as part of the ORDER By statement.

Is it possible to use in this way? or am I doing something wrong?

I was looking at /RestfullYii/ARBehaviors/ERestHelperScopes.php

The orderBy method, and the way on how the statement is build

public function orderBy($field, $dir = 'ASC') 
{
...
    $this->Owner->getDbCriteria()->mergeWith(
...
        $alias = $this->Owner->getTableAlias(false, false); //<-- this is a string index 'distance'*
        $dbCriteria['with'][$alias] = []; //<-- here the array is build ['distance' => 0]
        $dbCriteria['with'][$alias]['order'] = (!empty($dbCriteria['with'][$alias]['order'])? ', ': '') . $this->getSortSQL($property, $orderListItem['direction'], $alias);
..
}

Then I debug the /yiisoft/yii/framework/db/schema/CDbCriteria.php to figure out why the property was not included.

public function mergeWith($criteria,$operator='AND')
{
...
        if(empty($this->with))
            $this->with=$criteria->with;
        elseif(!empty($criteria->with))
        {
            $this->with=(array)$this->with;
            foreach((array)$criteria->with as $k=>$v)
            {
                if(is_integer($k))        //<-- here is looking for an integer index
                    $this->with[]=$v;
                elseif(in_array($k, $this->with))        //<-- here the array is [0 => 'distance']
                {
                    $excludes=array();
                    foreach(array('joinType','on') as $opt)
                    {
                        if(isset($this->with[$k][$opt]))
                            $excludes[$opt]=$this->with[$k][$opt];
                        if(isset($v[$opt]))
                            $excludes[$opt]= ($opt==='on' && isset($excludes[$opt]) && $v[$opt]!==$excludes[$opt]) ?
                                "($excludes[$opt]) AND $v[$opt]" : $v[$opt];
                        unset($this->with[$k][$opt]);
                        unset($v[$opt]);
                    }
                    $this->with[$k]=new self($this->with[$k]);
                    $this->with[$k]->mergeWith($v,$operator);
                    $this->with[$k]=$this->with[$k]->toArray();
                    if (count($excludes)!==0)
                        $this->with[$k]=CMap::mergeArray($this->with[$k],$excludes);
                }
                else
                    $this->with[$k]=$v;
            }
        }

I just get

  • When with is build on orderBy at ERestHelperScopes.php, a string index is used.
  • When CDbCriteria.php try to parse the with array, it looks for an integer index, or for a different arrangement of values on the array.

@jcvalerio :> Hmm... This is very strange... You should be able to do this and in fact it is test covered... I will look into it but it I may not be able to replicate your situation. Let me know if you are able to resolve this on your own.