Order by related data doesn't work - php

I have model with relations:
public function relations()
{
return array(
'fidistr' => array(self::BELONGS_TO, 'Distributors', 'fidistr_id', 'order'=>'fsname'),
'fitown' => array(self::BELONGS_TO, 'Town', 'fitown_id'),
'distributorsPointMails' => array(self::HAS_MANY, 'DistributorsPointMail', 'fidistr_point_id'),
'distributorsPointPhones' => array(self::HAS_MANY, 'DistributorsPointPhones', 'fidistr_point_id'),
);
}
I would like to order data by "fsname" from related table. I tried this:
$models = DistributorsPoint::model()->findAll('fitown_id=:id', array('id' => $_POST['city_id']));
but it still returns unsorted data. Help please.

The order on the relation is only used when lazy loading the relation. From the Yii guide on relations:
Note: when using eager loading such relation options as 'order',
'group', 'having', 'limit' and 'offset' will be ignored. You should
setup such parameters at the main model criteria level if you wish
them to be applied.
You can pass a criteria array instead of a string as the first parameter of findAll(). This will be used to initialize a CDbCriteria object. To order by a relation you need to eager load the relation using with():
$models = DistributorsPoint::model()
->with('fidistr')
->findAll(array(
'condition' => 'fitown_id=:id',
'order' => 'fidistr.fsname',
'params' => array(':id' => $_POST['city_id'])
));

Related

CakePHP 2.x containable + pagination for nested model

I have a problem with nested model pagination using containable in Cake...
I've got three models: Category, CompanyCategory, Company and there association is like this
Category hasMany CompanyCategory
CompanyCategory belongsTo Category
CompanyCategory belongsTo Company
Company hasMany CompanyCategory
I get data using contain, as shown below:
$options = [
'conditions' => ['Category.slug' => $slug],
'contain' => [
'CompanyCategory.Company.CompanyAddress'
]
];
return $this->find('first', $options);
Everything works properly, until I wanted to paginate the nested model - Company. I use CategoriesController with show method, which renders the view with the selected category and associated companies (Company hasMany Categories and Category hasMany Companies).
I've tried something like this:
$this->Paginator->settings = [
'limit' => 1,
'order' => [
'id' => 'asc'
],
'contain' => array('CompanyCategory.Company')
];
$data = $this->Paginator->paginate('Category.CompanyCategory.Company', array('Category.slug LIKE' => $slug));
$this->set('category', $data);
But this didn't work for me :(
Any suggestions / help?
If you define Category has a hasAndBelongsToMany relation, it would be easy for you. Thus you created a new Model called CompanyCategory, i assume there is a reason..
You can try this-
$this->Category->bindModel(
array(
'hasAndBelongsToMany' => array(
'Company'
)
)
);
$this->Paginator->settings = array(
'conditions' => array(
'Category.slug' => $slug
),
'limit' => 1,
'order' => array(
'id' => 'asc'
),
'contain' => array(
'Company'
)
);
I assume your relation table name is categorys_companies.... If not then you need take different approach
Finnaly I resolve my problem using
$this->Paginator->settings = array(
'limit' => 2,
);
$this->Paginator->paginate('Category.CompanyCategory.Company');
I forgot to write that I use method from CategoriesController, not Companies.
But now another problem blocked me... I use TranslateBehaviour, and data which I get has no translations...
Any idea? I googled a lot, but couldn't find any satisfactory solution.

Yii Display data from dataprovider of 2 models

How can I display "arrendatario_nombre" using a dataprovider in a Clistview
$dataProviderContratos = new CActiveDataProvider(ZfContratos::model(), array(
'keyAttribute'=>'zf_contrato_id',
'criteria'=>array(
'order' => 'contrato_fecha_ini',
'select' => 't.*, arr.arrendatario_nombre as arrendatario_nombre',
'join' => 'LEFT JOIN zf_arrendatarios arr ON arr.arrendatario_id = t.zf_arrendatarios_arrendatario_id',
'condition'=>'zf_inmuebles_inmueble_id=-1',
),
));
I tried:
$data->arrendatario_nombre
Thanks!
You can use Yii relations for this purpose,
http://www.yiiframework.com/doc/guide/1.1/en/database.arr#declaring-relationship
In your ZfContratos model file use the following and then you can call $data->arrendatario_nombre
public function relations() {
return array(
'arrendatario_nombre' => array(self::BELONGS_TO, 'zf_arrendatarios', 'zf_arrendatarios_arrendatario_id'),
);
}
Once this is declared in the model file you can use $data->arrendatario_nombre and also in any other place place you load the Zfcontratos model

CakePHP conditional find

I'm writing a simple Blog application. I am dealing with two models, BlogPost and BlogCategory.
They both have a HABTM relationship to each other using a separate table.
I have written a function in the BlogPost model to load all the posts from a certain category, but it keeps producing a database error.
public function getRecentFromCategory($category, $offset, $limit){
return $this->find('all', array(
'order' => 'BlogPost.date desc',
'offset' => $offset,
'limit' => $limit,
'conditions' => array('BlogCategory.id' => $category)
));
}
Why can't I make a conditional based on the associated categories?
You need to set up a belongsTo relationship between your models, meaning your BlogPosts can belong to a BlogCategory.
Assuming your BlogPost has a 'blog_category_id' field, in your BlogPost model:
public $belongsTo = array(
'BlogCategory' => array(
'className' => 'BlogCategory',
'foreignKey' => 'blog_category_id'
)
);
Then your find should be able to filter based on category in the way you want.

CakePHP how to retrieve HABTM data with conditions?

I use CakePHP 2.2.2
I have 3 tables: restaurants, kitchens and kitchens_restaurants - join table for HABTM.
In Restaurant model I have:
public $hasAndBelongsToMany = array(
'Kitchen' =>
array(
'className' => 'Kitchen',
'joinTable' => 'kitchens_restaurants',
'foreignKey' => 'restaurant_id',
'associationForeignKey' => 'kitchen_id',
'unique' => true,
'conditions' => '',
'fields' => 'kitchen',
'order' => '',
'limit' => '',
'offset' => '',
),
The problem is that I have separate controller for my main page in which I need to retrieve data from this models with complex conditions.
I added
public $uses = array('Restaurant');
to my main page controller and here comes the part where I need your advices.
I need to select only those restaurants where kitchen = $id.
I've tried to add
public function index() {
$this->set('rests', $this->Restaurant->find('all', array(
'conditions' => array('Restaurant.active' => "1", 'Kitchen.id' => "1")
)));
}
and I got SQLSTATE[42S22]: Column not found: 1054 Unknown column in 'where clause' error.
Obviously I need to fetch data from "HABTM join table" but I don't know how.
TLDR:
To retrieve data that's limited based on conditions against a [ HABTM ]'s association, you need to use [ Joins ].
Explanation:
The code below follows the [ Fat Model/Skinny Controller ] mantra, so the logic is mostly all in the model, and just gets called from a controller.
Note: You don't need all those HABTM parameters if you follow the [ CakePHP conventions ] (which it appears you are).
The below code has not been tested (I wrote it on this site), but it should be pretty darn close and at least get you in the right direction.
Code:
//Restaurant model
public $hasAndBelongsToMany = array('Kitchen');
/**
* Returns an array of restaurants based on a kitchen id
* #param string $kitchenId - the id of a kitchen
* #return array of restaurants
*/
public function getRestaurantsByKitchenId($kitchenId = null) {
if(empty($kitchenId)) return false;
$restaurants = $this->find('all', array(
'joins' => array(
array('table' => 'kitchens_restaurants',
'alias' => 'KitchensRestaurant',
'type' => 'INNER',
'conditions' => array(
'KitchensRestaurant.kitchen_id' => $kitchenId,
'KitchensRestaurant.restaurant_id = Restaurant.id'
)
)
),
'group' => 'Restaurant.id'
));
return $restaurants;
}
//Any Controller
public function whateverAction($kitchenId) {
$this->loadModel('Restaurant'); //don't need this line if in RestaurantsController
$restaurants = $this->Restaurant->getRestaurantsByKitchenId($kitchenId);
$this->set('restaurants', $restaurants);
}
There is a much cleaner way than the solution provided by Dave.
First you need to set a reverse HABTM Relationship between Restaurant and Kitchen in the Kitchen Model.
Than you just make a find for the Kitchen you are interested in (id = 1) and you will get the associated restaurants, using Containable Behavior for filtering by Restaurant fields.
$this->Restaurant->Kitchen->Behaviors->attach('containable'); // Enable Containable for Kitchen Model
$this->Restaurant->Kitchen->find('first', array(
'recursive' => -1 // don't collect other data associated to Kitchen for performance purpose
'conditions' => array('Kitchen.id' => 1),
'contain' => array('Restaurant.active = 1')
));
Source
You can not need use [join], because use have setting [ HABTM ]'s association
Kitchen model hasAndBelongsToMany Restaurant model so that you can code as bellow
KitchensControllers
<?php
public function index() {
$this->Kitchen->recursive = 0;
$kitchens = $this->Kitchen->find('all', array('contain' => array('Restaurant')));
$this->set('kitchens', $kitchens);
}
?>
Good luck!

containable on hasMany relationship

Greetings,
I am trying to tear down query returned from find call using containable in CakePHP.
for example I have 2 models, User and Post. User hasMany Post.
Now when I am using containable on find call like so:
$User->id = 1;
$User->find('first', array(
'fields' => array('id'),
'contain' => array('Post')
))
It will not return the associated Post, instead will just return the id of the user.
It works however if I am trying to fetch the data the other way around.
i.e this works:
$Post->find('first', array(
'fields' => array('id', 'user_id'),
'conditions' => array('Post.user_id' => 1),
'contain' => array('User')
))
this doesn't:
$Post->find('first', array(
'fields' => array('id'),
'conditions' => array('Post.user_id' => 1),
'contain' => array('User')
))
From the returned values I then suppose that for the containable to works, the foreignKey has to be in the fields.
How then would I be able to filter out the User fields on the first call as the association of user is stored in Post.user_id?
Any help is greatly appreciated! Thank's.
-aw
As larryb82 said you'll need to define the relationship in both directions in order to retrieve Posts data from the User model
A user has many posts.
A post belongs to an user
CakePHP Doc example

Categories