I have two tables:
evaluation_employees
Fields: id, username
evaluation_results
Fields: id, grade, evaluation_employee_id
In evaluation_results view I need to search the results (using the cakephp search plugin) by the employee's username, but in evaluation_results table I have the employee's id(evaluation_employee_id), not the username. I don't know how to make a link between those tables, to make it work.
Code in my view (evaluation_results/index.ctp):
echo $this->Form->create('EvaluationResult', array(
'url' => array_merge(array('action' => 'index'), $this->params['pass'])
));
echo $this->Form->input('username', array('div' => false, 'empty' => true)) . '<br/><br/>';
echo $this->Form->submit(__('Search', true), array('div' => false));
echo $this->Form->end();
Code in my controller (evaluation_results_controller.php):
var $components = array('Search.Prg');
function index() {
$this->Prg->commonProcess();
$this->EvaluationResult->recursive = 0;
$this->paginate = array(
'conditions' => $this->EvaluationResult->parseCriteria($this->passedArgs));
$this->set('evaluationResults', $this->paginate());
}
Code in my model (evaluation_result.php):
public $actsAs = array('Search.Searchable');
//Search fields data description for processing.
public $filterArgs = array(
array('name' => 'EvaluationEmployee.username', 'type' => 'query', 'method' => 'filterUsername')
);
//Method as decalred in $filterArgs to process the free form search.
public function filterUsername($data, $field = null) {
if (empty($data['EvaluationEmployee']['username'])) {
return array();
}
$username = '%' . $data['EvaluationEmployee']['username'] . '%';
return array(
$this->alias . '.EvaluationEmployee.username LIKE' => $username
);
}
Please tell me if more info is needed.
If you set up the associations in the model it will find all related records automatically when you search for an employee.
http://book.cakephp.org/1.3/en/view/1039/Associations-Linking-Models-Together
Related
In CakePHP I've a model Customer which looks like this:
<?php
class Customer extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
)
);
public function getDisplayName($id){
$customer = new Customer();
$customer_array = $customer->find('first', array(
'conditions' => array('Customer.id' => $id)
));
if($customer_array['Customer']['company']){
return $customer_array['Customer']['company'];
} else {
return $customer_array['Customer']['frontname'] . ' ' . $customer_array['Customer']['lastname'];
}
}
public function getFullName($id){
$customer = new Customer();
$customer_array = $customer->find('first', array(
'conditions' => array('Customer.id' => $id)
));
return $customer_array['Customer']['frontname'] . ' ' . $customer_array['Customer']['lastname'];
}
}
?>
In an other view (Project) I want to show a list of customers with there display name (because some of them have an company and others don't).
So in the ProjectController I added this:
$customers = $this->Project->Customer->find('list', array(
'fields' =>array(
'Customer.id', $this->Project->Customer->getDisplayName('Customer.id')
),
'conditions' => array(
'Customer.cloud_id' => '1'
)
));
$this->set('customers', $customers);
But then I get an MySQL error because the second field isn't a databasecolumn.
Who can help me with this question?
Your best best would be using virtual fields in your Customer model:
See the docs: http://book.cakephp.org/2.0/en/models/virtual-fields.html
<?php
class Customer extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
)
);
public $virtualFields = array(
'display_name' => 'IF(Customer.company IS NOT NULL, Customer.company, CONCAT_WS(' ', Customer.frontname, Customer.lastname))'
);
}
?>
Then in projects controller:
<?php
$customers = $this->Project->Customer->find('list', array(
'fields' =>array(
'Customer.id', 'Customer.display_name'
),
'conditions' => array(
'Customer.cloud_id' => '1'
)
));
$this->set('customers', $customers);
?>
To answer the question more generally (here the virtual fields solutions works fine), you could rewrite the getDisplayName function and put in in your Controller.
Then you could call it from the view using
$displayName= $this->requestAction(array(
'controller'=>'CustomersController',
'action'=>'getDisplayName ')
);
echo $displayName;
Hey guys I'm having trouble running an update query through a form in codeigniter. There is no error returned, but the query does not update in the database. It should be noted there's another form on the same page running an insert query that works fine.
View:
<?php
$modify = array(
'id' => 'modify-form',
'class' => ''
);
echo form_open('main/modify_idea', $modify);
$ta_modify = array(
'id' => $row->id,
'name' => 'ta_modify',
'label' => 'ta_modify',
'placeholder' => $row->idea,
'method' => 'Post'
);
echo form_textarea($ta_modify);
echo form_hidden('facebook_id', $session['id']);
echo "<div id='button'>";
echo form_submit('submit', 'Post');
echo "</div>";
echo form_close();
?>
Controller:
public function modify_idea() {
$this->load->model('idea');
$this->idea->modify_idea();
redirect('main/members');
}
Model:
public function modify_idea() {
$data = array(
'id' => $this->input->post('id'),
'idea' => $this->input->post('ta_modify'),
'facebook_id' => $this->input->post('facebook_id')
);
$query = $this->db->query("UPDATE idea SET `idea` = ? WHERE `id` =?", array($data['idea'], $data['id']));
return $query;
}
I've utilized the following resources but still no luck:
CodeIgniter MySQL query not working
CodeIgniter MySQL Query not returning any data, even though there definitely is data to be returned!
http://www.tutorialspoint.com/mysql/mysql-update-query.htm
https://www.codeigniter.com/userguide3/database/query_builder.html#deleting-data
As always, thanks for the help!
Pass your post data from controller to model
Change your controller code:
public function modify_idea() {
$this->load->model('idea');
$data = array(
'id' => $this->input->post('id'),
'idea' => $this->input->post('ta_modify'),
'facebook_id' => $this->input->post('facebook_id')
);
$this->idea->modify_idea($data);
redirect('main/members');
}
in model do this
public function modify_idea($data) {
$query = $this->db->query("UPDATE idea SET `idea` = ? WHERE `id` =?",
array($data['idea'], $data['id']));
return $query;
}
Please pass your post values to model from controller. Then it will work.
I have a site develop in cakephp 2.0.
I have a relation HABTM to the same model like this:
class Product extends AppModel {
public $name = 'Product';
public $useTable = 'products';
public $belongsTo = 'User';
public $actsAs = array('Containable');
public $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'ingredients_products',
'foreignKey' => 'product_id',
'associationForeignKey' => 'ingredient_id',
'unique' => false
)
);
}
I want to save a record into my view with a simple form like this:
echo $this->Form->create('IngredientProduct', array ('class' => 'form', 'type' => 'file'));
foreach ($product as $prod) {
echo '<div>'.$prod['ProductAlias']['alias'].'</div>';
echo $this->Form->input('IngredientProduct.product_id', array ('type'=>'text', 'value'=> $prod['ProductAlias']['id'], 'label'=> false, 'id' => 'id'));
}
$select = '<select name="data[IngredientProduct][ingredient_id]" id="[IngredientProductIngredientId">';
foreach ($other_product as $prod2) {
$select .= '<option value="'.$prod2['ProductAlias']['id'].'">'.$prod2['ProductAlias']['alias'].'</option>';
}
$select .= '</select><br>';
echo($select);
echo $this->Form->submit('Collega', array('id'=>'link_product'));
echo $this->Form->end();
Into my controller I save in this mode:
if ($this->Product->saveAll($this->request->data)){
$this->Session->write('flash_element','success');
$this->Session->setFlash ('Prodotto collegato con successo.');
//$this->redirect(array('action'=>'edit',$alias));
}
else{
$this->Session->write('flash_element','error');
$this->Session->setFlash('Errore di salvataggio activity');
}
When I'm going to see into the database I see that ingredient:id is setting well but product_id is 0.
I have debugged my request->data and this is the array:
array(
'IngredientProduct' => array(
'product_id' => '1',
'ingredient_id' => '2'
)
)
I have print the sql query created by cakephp:
INSERT INTO `db`.`ingredients_products` (`product_id`, `ingredient_id`, `modified`, `created`) VALUES ('', 2, '2012-10-09 23:19:22', '2012-10-09 23:19:22')
Why product_id is null instead of 1?
Can someone help me?
Thanks
I think this line is wrong:
$this->Product->saveAll($this->request->data);
Try:
$this->IngredientProduct->saveAll($this->request->data);
as your form seems to ask data for a relationship, not a new product.
Ok this is kind of hard to explain but I'll try my best.
I have 3 tables
companies products product_availabilities
--------- -------- ----------------------
id id id
name name company_id
product_id
buys (tinyint)
sells (tinyint)
And their models
class Company extends AppModel
{
public $name = 'Company';
public $hasMany = array(
'ProductAvailability'
);
class Product extends AppModel
{
public $name = 'Product';
public $hasMany = array(
'ProductAvailability'
);
class ProductAvailability extends AppModel
{
public $name = 'ProductAvailability';
public $belongsTo = array(
'Company',
'Product'
);
}
What I want to do is when I create a company, I want to be able to select products that the company buys or sells. I've seen an example of a hasMany through relationship in the book (http://book.cakephp.org/1.3/view/1650/hasMany-through-The-Join-Model) but they are creating the form from the "join table" controller. Is it possible to bind the productAvailability model to my company model to be able to select the products while creating the company?
Edit : Here is how I've done it. I know it is not optimal as there is a lot of looping involved but it works.
Company controller :
$products = $this->Company->ProductAvailability->Product->find('list', array('fields' => array('Product.id', 'Product.label')));
$this->set('products', $products);
if($this->request->is('post')){
if($this->Company->save($this->request->data)){
foreach($products as $product)
{
$tmpArray = array(
'company_id' => $this->Company->id,
'product_id' => $product['Product']['id']
);
foreach($this->request->data('BuyProducts.product_id') as $buyProduct)
{
if($buyProduct == $product['Product']['id'])
$tmpArray['buys'] = 1;
}
foreach($this->request->data('SellProducts.product_id') as $sellProduct)
{
if($sellProduct == $product['Product']['id'])
$tmpArray['sells'] = 1;
}
if(count($tmpArray) > 2)
{
$this->Company->ProductAvailability->create();
$this->Company->ProductAvailability->set($tmpArray);
$this->Company->ProductAvailability->save();
}
}
$this->Session->setFlash('Yay', 'success');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('Nay', 'error');
}
}
Company add form :
<?php echo $this->Form->create('Company'); ?>
<?php echo $this->Form->input('name', array( 'div' => 'full-form')); ?>
<?php echo $this->Form->input('BuyProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->input('SellProducts.product_id', array('multiple' => 'checkbox', 'options' => $products, 'div' => 'full-form', 'label' => false)); ?>
<?php echo $this->Form->end(array('label' => __('Save'), 'div' => 'center', 'class' => 'bouton-vert')); ?>
You have two options. Either let cakePHP do some magic with the hasAndBelongsToMany relationship or doing it manually which is necessary if you add attributes to the join table
1. CakePHP HABTM
Using the capabilities of CakePHP and making a straight forward solution I would make these changes:
Model
If one company has more than one product, and the products belong to many companies. It is a hasAndBelongsToMany relationship between Company<->Product
// company.php
...
var $hasAndBelongsToMany = array(
'Product' => array(
'className' => 'Product',
'joinTable' => 'companies_products',
'foreignKey' => 'company_id',
'associationForeignKey' => 'product_id',
'unique' => true,
)
);
...
// similar in product.php
Add the required table 'companies_products' in the database.
Controller
Then in the add function from the Company Controller there should be something like:
$products = $this->Company->Product->find('list');
$this->set(compact('products'));
View
Finally insert the products in the add.ctp, the select should allow multiple selections and let cakePHP do some magic, like this:
echo $this->Form->input('products', array(
'label' => 'Products to buy (Ctr+multiple choice)'
'type' => 'select',
'multiple' => true,
));
2. Manually
When the HABTM becomes more 'exotic' and includes some attributes like in your case 'buy' or 'sell' you need to do the manual way. This is in the Product Controller setting manually the fields before inserting them in the database. Something like:
foreach($availableProducts as $availableProduct ){
$this->Product->ProductAvailabilities->create();
$this->Product->ProductAvailabilities->set( array(
'company_id' => $this->Product->id,
'product_id' => $availableProduct['Product']['id'],
'buys' => $availableProduct['Product']['buy'],
'sells' => $availableProduct['Product']['sell']
// or however you send it to the controller
));
$this->Product->ProductAvailabilities->save();
}
Let's hope this helps you ...
you are planning a habtm-relationship (m:n) with the possibility to have extra fields in the join table. Even though this can be done with regular habtm I prefer the way you choose and implement the m:n as 1:n:1, which is simply the same and gives you more options when saving your data.
Here is a similar question and answer
As for your question: You can collect the the data from your products table like this:
$this->Company->ProductAvailability->Product->find('all', $params);
Also you might want to have a look at the containable-behaviour which is very useful for this use case:
$params['conditions'] = array(
'Company.id' => $id
);
$params['contain'] => array(
'ProductAvailability' => array(
'conditions' =>array(
'buys' => 1
),
'Product' => array(
'order' => array(
'name' => 'ASC'
)
)
)
);
$this->Company->find('all', $params);
I'm using cakephp, I have a model "comment" with two fields : "model_type" and "model_id" in order to comment every item of my application (eg Picture, News, Article, ...) with a single Comment model.
I wonder how to make this. (A component "Comment" for controller that could be commented ?)
Finally I want to list comment in view just with a helper:
$comment->show('model_name', 'item_id');
that would display correctly paginated comments and a form for adding a new comment to the item.
Thanks.
Edit: See this too : http://bakery.cakephp.org/articles/AD7six/2008/03/13/polymorphic-behavior
The Solution
A multi model commenting system and pagination just with :
<?php echo $this->element('comments',
array(
'model_type' => "model_name",
'model_id' => $data['model']['id'],
'order_field' => 'created',
'order' => 'asc')); ?>
The model
Scheme :
- id
- model_type
- model_id
- content
(optional:)
- user_id
- created
- updated
- rating
- ...
The Comment Model :
// {app}/models/comment.php
class Comment extends AppModel{
public $name = 'Comment';
// List of model that could be commented
protected $model_list = array(
'news' => array(
'name' => 'News', // here it's the model's name
'field' => 'validated'), // A field for validation ( allow comments only on validaded items)
'articles' => array(
'name' => 'Article',
'field' => 'validated')
);
// This is an example
public $belongsTo = array(
'User' => array(
'conditions' => 'User.validated = true'
)
);
public $validate = array(
'model_type' => array(
'rule' => 'checkModelType',
'message' => "Something goes wrong !"
),
'model_id' => array(
'rule' => 'checkModelId',
'message' => "Something goes wrong !"
),
'content' => array(
'rule' => 'notEmpty',
'message' => "Empty content !"
)
);
// Check if the model is commentable
public function checkModelType($data){
$model_type = $data['model_type'];
return in_array($model_type, array_keys($this->model_list));
}
// Check if the item exists and is validated
public function checkModelId($data){
$model_id = intval($data['model_id']);
$model = $this->model_list[$this->data['Comment']['model_type']];
$params = array(
'fields' => array('id', $model['field']),
'conditions' => array(
$model['name'].'.'.$model['field'] => 1, // Validated item
$model['name'].'.id' => $model_id
)
);
// Binding model to Comment Model since there is no $belongsTo
return (bool) ClassRegistry::init($model['name'])->find('first', $params);
}
}
The Controller
// {app}/controllers/comments_controller.php
class CommentsController extends AppController
{
public $name = 'Comments';
// Pagination works fine !
public $paginate = array(
'limit' => 15,
'order' => array(
'Comment.created' => 'asc')
);
// The action that lists comments for a specific item (plus pagination and order !)
public function view($model_type, $model_id, $order_field = 'created', $order = 'DESC'){
$conditions = array(
'Comment.model_type' => $model_type,
'Comment.model_id' => $model_id
);
// (optional)
if($order_field != 'created') {
$this->paginate['order'] = array(
'Comment.'.$order_field => $order,
'Comment.created' => 'asc');
}
// Paginate comments
$comments = $this->paginate($conditions);
// This allow to use paginator with requestAction
$paginator = ClassRegistry::getObject('view')->loaded['paginator'];
$paginator->params = $this->params;
return compact('comments', 'paginator');
}
public function add(){
// What you want !
}
}
The views
Comments element
/* {app}/views/elements/comments.ctp
#params : $model_type
* : $model_id
*
* */
$result = $this->requestAction("/comments/view/$model_type/$model_id/$order_field/$order/", $this->passedArgs);
$paginator = $result['paginator'];
$comments = $result['comments'];
$paginator->options(array('url' => $this->passedArgs));
?>
<h2>Comments</h2>
<fieldset class="commentform">
<legend>Add un commentaire</legend>
<?php
// Form
echo $form->create('Comment', array('action' => 'add'));
echo $form->hidden('model_type', array('value' => $model_type));
echo $form->hidden('model_id', array('value' => $model_id));
echo $form->input('content');
<?php
echo $form->end('Send');
?>
</fieldset>
<div class="paginationBar">
<?php
echo $paginator->prev('<< ', null, null, array('class' => 'disabled'));
echo '<span class="pagination">',$paginator->numbers(),'</span>';
echo $paginator->next(' >>', null, null, array('class' => 'disabled'));
?>
</div>
<?php
foreach($comments as $comment){
echo $this->element('comment', array('comment' => $comment));
}
?>
<div class="paginationBar">
<?php
echo $paginator->prev('<< ', null, null, array('class' => 'disabled'));
echo '<span class="pagination">',$paginator->numbers(),'</span>';
echo $paginator->next(' >>', null, null, array('class' => 'disabled'));
?>
<p><br />
<?php
echo $paginator->counter(array('format' => 'Page %page% on %pages%, displayi %current% items of %count%'));
?>
</p>
</div>
Comment element
//{app}/views/elements/comment.ctp
// A single comment view
$id = $comment['Comment']['id'];
?>
<div class="comment">
<p class="com-author">
<span class="com-authorname"><?=$comment['User']['name']?> </span>
<span class="com-date">(<?=$comment['Comment']['created']?>)</span>
</p>
<p class="com-content"><?=$comment['Comment']['content']?></p>
</div>
hm... it would be pretty complicated if you want to display paginated comments like that. You should use lazy loading: don't actually load the comments until the user click on it or something.
You should probably make an element. you can pass model_name and model_id to it. And in the element, you can create a comment 'widget' that can directly send the comment to your comments controller, using ajax; and load the paginated comments using ajax also.
Check out this plugin (it's actually a component) developed by CakeDC.
You could either implement that or, use that to create your own solution.