I have one controller for invoices and another for clients.
I have made some "relationships" in the models of these controllers as below:
Client.php
<?php
class Client extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
}
?>
Invoice.php
<?php
class Invoice extends AppModel {
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
}
?>
So I thought that making a drop down with each client would be easy. Although, I can't figure out how to do this.
First off this is what I want as a result:
<select>
<option value="1">Client Name</option>
</select>
Where value is equal to id in client table and Client Name is equal to name in client table.
I tried placing the following into the invoices controleler:
$client = $this->Client->find('all');
and then the following into my view:
echo $this->Form->select('client_name',client, array(
'class' => 'form-control',
'name' => 'client_id'
));
But I received the following error:
Call to a member function find() on a non-object
Directly on page load. What do I need to do to make this work?
More than likely, your problem is that the Client model is not automatically loaded in the Invoices controller. Since Client has a relationship with Invoice, you can call find on Client like this instead:
$data = $this->Invoice->Client->find('list', array('fields' => array('id', 'name')));
$this->set('clients', $data);
Then in the view,
echo $this->Form->select('Invoice.client_id', $clients);
or
echo $this->Form->input('Invoice.client_id', array('type' => 'select', 'options' => $clients));
This should output a dropdown where the values are the client id's and the visible options in the drop down are the client names. You will want to go by id's rather than client names when associating invoices with the clients.
Related
I've been successful in creating an extra table in the prestashop products table throught rest api of webservice , however the api link http://127.0.0.1/prestashop/api/wb3d/1 wb3d is the new table which I have created in webservice . Which holds a path to an images directory somewhere on the web . This link when opened shows the data which has been saved in the database as seen in the following image below
model is directory name on the web, so this api(wb3d) has been associated with the product table in the webservice the link:http://127.0.0.1/prestashop/api/products/1 when I open this link . The entry of the association is shown but the data is not shown **refer the below image **
The highlighted area shows the wb3d table associated with the product table throught rest api of webservice . I'm unable to associate the wb3d tale data with product table data. So I can use it in other devices through webservice
This is what I have tried so far
<?php
class ProductMergeCore extends ObjectModel
{
public $product_id;
public $id_wb3d;
public $directory_name;
public static $definition = array(
'table' => 'wb3d',
'primary' => 'id_wb3d',
'fields' => array(
'id_wb3d' => array('type' => self::TYPE_INT, 'required' => true),
'product_id' => array('type' => self::TYPE_INT, 'required' => true),
'directory_name' => array('type' => self::TYPE_STRING, 'required' =>false, 'size' => 64),
),
);
protected $webserviceParameters = array();
}
?>
productmerge.php is responsible for creating an associate table entry in product table.
<?php
Class Product extends ProductCore
{
public $extrafield;
public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null)
{
$this->webserviceParameters['associations']['wb3d'] = array('resource' => 'wb3d','fields' => array('directory_name' => array('required' => true)));
parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
}
}
?>
In this product.php which is for overriding the product class for passing the extra parameters through webserviceparameters() and then calling the parent constructor of the product class
<?php
class WebserviceRequest extends WebserviceRequestCore
{
public static function getResources()
{
$resources=parent::getResources();
$resources['wb3d'] = array('description' => 'images path', 'class' => 'ProductMerge');
ksort($resources);
return $resources;
}
}
?>
WebserviceRequest.php class is a override class for the WebserviceRequest class which shows the description of the table entry in the webservice
These are the files which are required to get the things done. What I'm trying to achieve is the associated table (wb3d) data should be available within the products table through webservice rest api call.
if u want to add other webservice table as your association to your product , you can take a look at how associations is done in category.php located in prestashop/classes.
'associations' => array(
'categories' => array('getter' => 'getChildrenWs', 'resource' => 'category', )
)
as you can see there is a parameter named getter which gets the value from
getChildrenWs which is a method in category.php which fetches the data from database.
so in your case: in Product.php
$this->webserviceParameters['associations']['wb3d'] = array('resource' => 'wb3d',
'getter' => 'yourMethodName',
'fields' => array('directory_name' => array('required' => true));
and create a method named 'yourMethodName' in Product.php
public function yourMethodName()
{
//copy the getChildrenWs method which is in Category.php and alter it to ur needs
}
I just cant get data from 2 tables in a HABTM relationship and I cant get the answer for these cakephp docs (again). Sorry for asking the question on something that should be explained in the docs.
This should be a simple but I keep getting undefined index and the relationship I set up seems in accordance with the docs. I have another post on a more complicated matter but this issue needs to be isolated .
I dont know how to get related data from the lessons table and the students table via this lessons-students HABTM table.
I want all the lessons a student does. I want the name of the student from the student table and lesson details from the lesson table which has lesson_id as the common link in this lessons-students table. Sounds simple but I cant do it.
public $hasAndBelongsToMany = array(
'Student' => array(
'className' => 'Student',
'joinTable' => 'lessons_students',
'foreignKey' => 'lesson_id',
'associationForeignKey' => 'student_id',
'unique' => 'keepExisting',
)
);
class LessonsController extends AppController {
....
$this->Lesson->recursive = -1;
$options['joins'] = array(
array('table' => 'lessons_students',
'alias' => 'LessonsStudent',
'type' => 'LEFT',
'conditions' => array(
'Lesson.id = LessonsStudent.lesson_id',
)
),
array('table' => 'students',
'alias' => 'Student',
'type' => 'LEFT',
'conditions' => array(
'LessonsStudent.student_id=Student.id',
)
),
);
$options['conditions'] = array('Student.id' => 2);
// $Item->find('all', $options);
$student=$this->set( 'student',$this->Lesson->find('all', $options));
In the view I get the error undefined index Student
<?php
// debug($student);
foreach ($student as $item2):
echo '<td>'. $item2['Lesson']['id'].'</td>';
echo '<td>'. $item2['Student']['id'].'</td>';
http://stackoverflow.com/questions/17250215/cant-get-all-user-data-from-habtm-in-cakephp
http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm
If you want to use model association you need to remove $this->Lesson->recursive = -1; because it disable any associations defined in model. And than you can remove $options['joins'].
If you have defined many association in your Lesson model and don't want to fetch all of it use unbindModel() or use Containable behavior
$this->Lesson->Behaviors->load('Containable');
$this->Lesson->contain('Student');
If you need to do find many times in many actions it's better to enable Containable in model itself
class Lesson extends AppModel {
public $actsAs = array('Containable');
}
so you can avoid $this->Lesson->Behaviors->load('Containable'); line;
Okay, so I have a form in CakePHP that submits to a database. In this form it submits a field called client_id and it is stored in the database as such as well.
Then I have a view to allow me to view all of the invoices that have ever been created. To view the client responsible for the invoice, I can currently only see the id entered in the form by placing: <?php echo $invoice['Invoice']['client_id']; ?> in the view.
The invoices go to one database called: invoices
The clients name is not stored in the invoices table, just the id
The clients information is stored in one database called: clients
I want to be able to actually display out the clients real name in the invoices view rather than the client id.
I tried adding the following query to my index controller, But i'm not sure what to do after this or if this is even right.
$this->set('clients', $this->Invoice->query("SELECT * FROM clients WHERE id='89545'"));
In order to keep this question short in the first place, Please request specific code by commenting. i.e. Controller code, view code, etc... Thank you in advance.
Additional Thoughts
If I wasn't using CakePHP I could use something like the following, So I guess I just don't know how to put this into cakephp "language".
<?php
query($con, "SELECT name FROM clients WHERE id='$client_id'");
echo $row['name'];
?>
roughly!
Update
Here are my models
First one being the Client.php
<?php
class Client extends AppModel {
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
}
?>
Second one being the Invoice.php
<?php
class Invoice extends AppModel {
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
}
?>
And finally, to get my invoices from the database, I am using the following inside: InvoicesController.php
public function index() {
$this->set('invoices', $this->Invoice->find('all'));
}
Have you properly set up your model associations? If so you should be able to do something like $invoice['Client']['client_name'] assuming you didn't use recursive = -1.
/edit: Ok I don't mind throwing some code out, but this is a fundamental concept you'll have to try to wrap your head around. Every model that is connected to another model has to have the association set up or things will be painful.
I am assuming a Client hasMany Invoice. So each invoice is specific to a client, and they can have multiple invoices (ex. October 2013 vs November 2013 invoice). From the CakePHP page we see:
class User extends AppModel {
public $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'foreignKey' => 'user_id',
'conditions' => array('Comment.status' => '1'),
'order' => 'Comment.created DESC',
'limit' => '5',
'dependent' => true
)
);
}
So using that as our template, we end up with:
public $hasMany = array(
'Invoice' => array(
'className' => 'Invoice',
'foreignKey' => 'client_id'
)
);
And that goes in Client.php. As the inverse of hasMany is belongsTo, we have an Invoice belongsTo Client. Again, using the CakePHP page as the template, we end up with:
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'foreignKey' => 'client_id'
)
);
And that goes in Invoice.php. Once you set up those associations, whenever you do something like $this->Invoice->find('all'); or $this->paginate('Invoice');, with proper $recursive settings, Cake will grab the corresponding Client record. This allows you to do what I said before, something like $invoice['Client']['client_name'].
You can also use the $actsAs = array('Containable'); in the model in order to use the 'contain' directive in your controller's find method (instead of using recursive which most likely will get unwanted data on models with many relations)
I have got stuck on Multilevel associated tables in Cake PHP code.
I have the following models
Guardian who has many students and the various students have their studentfees. When I create a guardian with 2 students, an associated 2 row must be created for StudentFees table. Im successful in adding 2 students when adding a guardian, but I dont know how to add the 2 rows of fees for the student. My code is as below.
class Guardian extends AppModel {
public $name = 'Guardian';
public $recursive =2;
public $hasMany = array(
'Student' => array(
'className' => 'Student',
'dependent' => true
)
);
}
class Student extends AppModel {
public $name = 'Student';
public $hasMany = array(
'StudentFee' => array(
'className' => 'StudentFee',
'dependent' => true
)
);
}
class StudentFee extends AppModel {
public $name = 'StudentFee';
public $belongsTo = array(
'Student' => array(
'className' => 'Student',
'dependent' => true
)
);
}
Pl help me to save the studenFee details too. I use SaveAssociated function that saves guardian and Student details.
If I understood you correctly, this should do the trick:
Model::saveAll() should take care of it for you and select the appropriate method, saveMany or saveAssociated. Moreover, it will automatically set your foreignKeys so everything is neatly inserted into the database.
$this->Guardian->saveAll(array('Guardian' => array(
[...],
'Student' => array(
0 => array(
[here's your first Student],
'StudentFee' => array(
0 => array(
[here's your first StudentFee]
)
)
)
)
)));
can use saveAll and saveAssociated methods.
You can try using this method, which i always use in such situations :
$this->Studentfee->create();
$this->Studentfee->set(array(
'field1' => 'value',
'field2' => 'value'
));
$this->Studentfee->save();
and you can put in a loop for all student fees
I have a table called websites and a table called clients
Clients has many websites and a website belongs to a client
Now for this i have created the following connection in my Models:
class Website extends AppModel
{
public $belongsTo = array(
'Client' => array(
'className' => 'Client',
'dependent' => false,
'foreignKey' => 'client_id'
)
);
}
class Client extends AppModel
{
public $hasMany = array(
'Website' =>array(
'className' => 'Website',
'dependent' => true,
'foreignKey' => 'client_id'
)
);
Now whenever a client goes to edit the client should ONLY be able to edit the website ids that belongs to that user.
However in my case any client is able to edit any websites.
is there a way to deny them access without hardcoding a check at the controller?
I mean there should be a way that the magic in cake can find only websites that belongs to that clientid
Now, if you have properly set the Auth Component with Client Model, i mean that one client can not modify other client, but you need to cross check for the website they are editing belongs to them or not this might help..
public function _check_member($client,$website){
$this->loadModel('Website');
$options = array(
'conditions' => array('Website.client_id' => $client,'Website.id' => $website),
'recursive' => 0
);
$website = $this->Website->find('first', $options);
if($website){
return true;
}else{
return false;
}
}
and you will call the function with $this->_check_member($client_id,$website_id); Now only to the client this website belongs to will return 1.
But if your clients are able to edit one another, you should look into auth component. here is a video tutorial Auth Component setup , if you are having problems setting up auth component using the client model because every tutorial shows how to do it with user model, which is default, let me know in the comments.