I'm working on a project where I want to search for people based on skills they say they have on their profile. I want to use the findAllBy(); function but I'm not sure how this works with the Pagination component packaged with CakePHP.
Just use conditions in Paginator, like :
public function skills($skill = null){
$this->Paginator->settings = array(
'conditions' => array(
'skill LIKE' => '%'.$skill.'%'
)
);
$people = $this->Paginator->paginate('People');
$this->set('people', $people);
}
I'm new to CakePHP and I'm still learning the basics, through working in a live project and taking help from the CakePHP documentations when necessary. Currently, I'm having the following problem : I've recently changed my database table name and structure, so I was forced to change my view, controller and model names. After changing names, whenever I run the index.ctp page, I get the following error:
Fatal error: Call to undefined method stdClass::read() in C:\wamp\www\sdb\app\controllers
\home_loan_distributions_details_controller.php on line 32
Previously, my view folder was named home_loan_distributions, now it's renamed to home_loan_distributions_details.
My previous controller name was home_loan_distributions_controller.php and current name is home_loan_distributions_details_controller.php. The codes:
class HomeLoanDistributionsDetailsController extends AppController {
var $name = 'HomeLoanDistributionsDetails';
function index() {
$user = $this->Session->read('User');
$user_role = $user['User']['user_role_id'];
$actions = $this->Session->read('actions');
$display_actions = array();
foreach ($actions as $action) {
array_push($display_actions, $action['pm_controller_actions']['name']);
}
$this->set('display_actions', $display_actions);
$this->set('user_role', $user_role);
$branch_id = 18;
$this->set('branch_id', $branch_id);
$conditions = array('branch_id' => $branch_id);
$this->set('HomeLoanDistributionsDetails', $this->paginate($conditions));
$this->HomeLoanDistributionDetail->Branch->recursive = 0;
$this->set('BranchDetailInformation', $this->HomeLoanDistributionDetail->Branch->read(array('Branch.id', 'Branch.name', 'RegionalOffice.name', 'DistrictOffice.name', 'SubDistrictOffice.name', 'ClusterOffice.name'), $branch_id));
}
My model was previously named home_loan_distribution.php and now it's named home_loan_distribution_detail.php. The codes:
class HomeLoanDistributionDetail extends AppModel {
var $name = 'HomeLoanDistributionDetail';
var $actsAs = array('Logable' => array(
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'list', // options are 'list' or 'full'
'description_ids' => TRUE // options are TRUE or FALSE
));
var $validate = array(
'entry_date' => array(
'rule' => 'date',
'message' => 'Enter a valid date',
'allowEmpty' => true
),
'branch_id' => array('numeric'),
'customer_id' => array('numeric'),
'loan_amount' => array('numeric'),
'service_charge' => array('numeric'),
'security' => array('numeric'),
'loan_taken_term' => array('numeric'),
'purpose_id' => array('numeric'),
'installment_amount' => array('numeric'),
'installment_service_charge' => array('numeric'),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
var $belongsTo = array(
'Branch' => array(
'className' => 'Branch',
'foreignKey' => 'branch_id',
'conditions' => '',
'fields' => 'id,name',
'order' => ''
)
);
function paginate($conditions, $fields, $order, $limit, $page = 1, $recursive = null, $extra = array()) {
$recursive = 0;
$group = $fields = array('branch_id', 'entry_date');
$order = array('entry_date DESC');
$limit = 4;
$this->paginateCount($conditions);
return $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'recursive', 'group'));
}
function paginateCount($conditions = null, $recursive = 0, $extra = array()) {
$recursive = 0;
$group = $fields = array('branch_id', 'entry_date');
$order = array('entry_date DESC');
$results = $this->find('all', compact('conditions', 'fields', 'order', 'limit', 'page', 'recursive', 'group'));
return count($results);
}
}
What my guess is: probably I messed up the naming conventions while renaming everything. The problem is definitely within this line in the controller:
$this->set('BranchDetailInformation',
$this->HomeLoanDistributionDetail->Branch->read(array('Branch.id', 'Branch.name',
'RegionalOffice.name', 'DistrictOffice.name', 'SubDistrictOffice.name', 'ClusterOffice.name'),
$branch_id));
Whenever I comment out this line, I stop getting the above mentioned error message and my view page loads (although that still have some data missing - because I need those Branch related data to be displayed in my view.)
I can't figure out what exactly my problem is, but at least I know where it is. I need someone to pinpoint it.
My CakePHP version is 1.2.5, PHP version - 5.2
There is no function read for model.If you want to find some model data then try with -
$this->set('BranchDetailInformation', $this->HomeLoanDistributionDetail->Branch->find('all', $consitions);
$conditions will be the array of all requirements you want to provide. See the docs for more info.
Apparently, the problem seemed to be related to my 'className' => 'Branch' element of the Branch array used in my model, since the stdClass::read() method is related to classes and not models. But I discovered that the problem was elsewhere. This error was part of that problem, but it itself is not the actual problem.
I figured out this morning that my Model name is HomeLoanDistributionDetail, but my table name is home_loan_distributions_details (because someone else has changed the table name). CakePHP convention requires corresponding table name to be plural and model class name to be singular and CamelCased.
Quoting from the CakePHP Cookbook:
Model class names are singular and CamelCased. Person, BigPerson, and ReallyBigPerson are all examples of conventional model names.
Table names corresponding to CakePHP models are plural and underscored. The underlying tables for the above mentioned models would be people, big_people, and really_big_people, respectively.
Considering the above convention, I just had to rename my model class name from HomeLoanDistributionDetail to HomeLoanDistributionsDetail, in order to match with the table name home_loan_distributions_details. Also, I had to change the model file name from home_loan_distribution_detail.php to home_loan_distributions_detail.php.
After doing that, I stopped getting the error and I was successful in retrieving data from table and viewing it.
I have two models called Batch and User
Batch has the following
public $belongsTo = array(
'Customer' => array(
'className' => 'User',
'foreignKey' => 'customer_id',
'conditions' => array('Customer.group_id' => CUSTOMERS),
'fields' => '',
'order' => '',
),
);
When I do the following:
$customers = $this->Batch->Customer->find('list');
I fully expected to get back just the users whose group_id matches CUSTOMERS. It returns ALL the records in the users table.
However, I actually have to write
$customers = $this->Batch->Customer->find('list', array('conditions' => array('Customer.group_id' => CUSTOMERS)));
Is there a way so that the chained model User knows that it is called as Customer by Batch and therefore automatically reads the correct conditions in the associations found in Batch model?
I want to make my code more readable hence the motivation for this question.
I want to write simply
$customers = $this->Batch->Customer->find('list');
or something similarly straightforward.
Of course, I realized that if I do the following:
$batches = $this->Batch->find('all');
The condition stated in the associations will be used. But I don't want to find batches. I want to find just customers.
I am using CakePHP 2.4
I think you can't
but you can create custom find types in User model file
public $findMethods = array('customer' => true); //this enable a custom find method named 'customer'
protected function _findCustomer($state, $query, $results = array()) {
if ($state === 'before') {
$query['conditions'] = array('group_id' => CUSTOMERS);
}
return parent::_findList($state, $query, $results);
}
and in BatchesController
$this->Batch->Customer->find('customer');
There are several ways to do this.
1)
do nothing.
Continue to use code like
$customers = $this->Batch->Customer->find('list', array('conditions' => array('Customer.group_id' => CUSTOMERS)));
2)
create a custom find method as suggested by arilia.
3)
write a getCustomers method inside Batch model
where it looks something like this:
public function getCustomers($type, $query = array()) {
if (empty($query['conditions'])) {
$query['conditions'] = array();
}
$query['conditions'] = array_merge($query['conditions'], array('Customer.group_id' => CUSTOMERS));
return $this->Customer->find($type, $query);
}
then you can call
$customers = $this->Batch->getCustomers('list');
UPDATE:
I have written a Plugin that helps with this kind of behavior, utilizing the 3rd solution.
class Batch extends AppModel {
public $name = 'Batch';
public $actsAs = array('UtilityBehaviors.GetAssoc');
public $belongsTo = array(
'Customer' => array(
'className' => 'User',
'foreignKey' => 'customer_id',
'conditions' => array('Customer.group_id' => 7),
'fields' => '',
'order' => '',
),
);
}
You can fetch just the customer data when you are in BatchesController this way:
$customers = $this->Batch->getAssoc('Customer', 'list');
$customers = $this->Batch->getAssoc('Customer', 'all');
$customerCount = $this->Batch->getAssoc('Customer', 'count');
This behavior has tests at travis and you can read about the tests written at github.
I've just baked a simple CakePHP app, and I'm trying to customize how records are paginated. I have this action in my controller:
public function index() {
$this->Recipe->recursive = 0;
$this->set('recipes', $this->Recipe->paginate());
}
This works fine with the default pagination. I'm trying to customize the amount of rows returned and their order by using a class property called $paginate in the same controller:
public $paginate = array(
'limit' => 1,
'order' => array(
'Recipe.title' => 'asc'
)
);
However it's taking no effect at all. The results still have the default limit and sort order. I've also tried setting up $this->paginate in my action, however this seems to get ignored also:
public function index() {
$this->paginate = array(
'limit' => 1,
'order' => array(
'Recipe.title' => 'asc'
)
);
$this->set('recipes', $this->Paginator->paginate());
}
What could be causing Cake to ignore the pagination options I'm setting? Does it perhaps do something funky when you bake the application which I'm not aware of?
Try
public function index() {
$this->Paginator->settings = array(
'limit' => 1,
'order' => array(
'Recipe.title' => 'asc'
)
);
$this->set('recipes', $this->Paginator->paginate());
}
I'm trying to create a single, one-off page that will combine information from several models. This is the code I'm trying to use:
public function index() {
$this->loadModel('people');
$this->people->find('all', array(
'order'=>'people.last_name ASC',
'conditions' => array(
'People.member =' => '1',
),
));
$this->set('people', $this->paginate('people') );
}
But it seems that my call to find() has no impact on $this->set(), and I don't understand why.
public function index() {
$this->loadModel('people');
$findPeople = $this->people->find('all', array(
'order'=>'people.last_name ASC',
'conditions' => array(
'People.member =' => '1',
),
));
$this->set('people', $findPeople);
}
I think paginate will ignore your conditions unless you put the conditions in the paginate...