I'm coding an app to sell cars, so i have a model called Anuncio(part that show the car, its in portuguese i dont know translate it) that has one Carmodel and Carmodel has one CarMake.
On anuncio controller i want load all Makes to populate combobox, so i'm using that:
$makes = $this->Anuncio->Carmodel->CarMake->find('list');
its working properly, but that find is bringing all makes, i want bring just makes that have at least one Carmodel recorded (something like INNER JOIN rather LEFT JOIN).
thanks
Hello you didn't provide any code so I won't give you exact answer but I will write how it can be done.
You should override the model's list method and specially list action
class Carmodel extends AppModel {
var $belongsTo = array('User');
function find($type, $queryData = array()) {
switch ($type) {
case 'list':
//do the query that joins tables in way you want
default:
return parent::find($type, $queryData);
}
}
}
More can be found on http://debuggable.com/posts/implementing-different-types-for-cakes-modelfind-method:485030de-4778-456e-8400-44d84834cda3
I hope that it helps you. You can create your own $type in this method you don't need to override list action but you can create your own or just create new method in Carmodel
Related
I'm currently struggling with retrieving data towards a parent model. I'll drop my database, classes, and things I've tried before.
I have 4 tables: sales_orders, products, work_orders, and product_sales_order (pivot table between sales_orders and products).
SalesOrder.php
class SalesOrder extends Model
{
public function products()
{
return $this->belongsToMany(Product::class)
->using(ProductSalesOrder::class)
->withPivot(['qty', 'price']);
}
}
ProductSalesOrder.php
class ProductSalesOrder extends Pivot
{
public function work_orders()
{
return $this->hasMany(WorkOrder::class);
}
public function getSubTotalAttribute()
{
return $this->qty* $this->price;
}
}
WorkOrder.php
class WorkOrder extends Model
{
public function product_sales_order()
{
return $this->belongsTo(ProductSalesOrder::class);
}
public function sales_order()
{
return $this->hasManyThrough(
ProductSalesOrder::class,
SalesOrder::class
);
}
}
So, what I want to retrieve sales order data from work order since both tables don't have direct relationship and have to go through pivot table and that is product sales order. I've tried hasOneThrough and hasManyThrough but it cast an error unknown column. I understand that error and not possible to use that eloquent function.
Is it possible to retrieve that sales order data using eloquent function from WorkOrder.php ?
You cannot achieve what you want using hasOneThrough as it goes from a table that has no ID related to the intermediate model.
In your example you are doing "the inverse" of hasOneThrough, as you are going from a model that has the ID of the intermediate model in itself, and the intermediate model has the ID of your final model. The documentation shows clearly that hasOneThrough is used exactly for the inverse.
So you still should be able to fix this, and use a normal relation as you have the sales_orders_id in your model SuratPerintahKerja, so you can use a normal relation like belongsTo to get just one SalesOrder and define it like this:
public function salesOrder()
{
return $this->belongsTo(SalesOrder::class, 'sale_orders_id');
}
If you want to get many SalesOrders (if that makes sense for your logic), then you should just run a simple query like:
public function salesOrders()
{
return $this->query()
->where('sale_orders_id', $this->sale_orders_id)
->get();
}
Have in mind that:
I have renamed your method from sales_order to salesOrder (follow camel case as that is the Laravel standard...).
I have renamed your method from sales_order to salesOrders for the second code as it will return more than 1, hence a collection, but the first one just works with one model at a time.
I see you use sale_orders_id, but it should be sales_order_id, have that in mind, because any relation will try to use sales_order_id instead of sale_orders_id, again, stick to the standards... (this is why the first code needs more parameters instead of just the model).
All pivot tables would still need to have id as primary and auto incremental, instead of having the id of each related model as primary... Because in SuratPerintahKerja you want to reference the pivot table ProdukSalesOrder but it has to use both produks_id (should have been produk_id singular) and sale_orders_id (should have been sales_order_id). So if you were able to use something like produk_sales_order_id, you could be able to have better references for relations.
You can see that I am using $this->query(), I am just doing this to only return a new query and not use anything it has as filters on itself. I you still want to use current filters (like where and stuff), remove ->query() and directly use the first where. If you also want to add ->where('produks_id', $this->produks_id) that is valid and doesn't matter the order. But if you do so, I am not sure if you would get just one result, so ->get() makes no sense, it should be ->first() and also the method's name should be salesOrder.
Sorry for this 6 tip/step, but super personal recommendation, always write code in English and do not write both languages at the same time like produks and sales orders, stick to one language, preferrably English as everyone will understand it out of the box. I had to translate some things so I can understand what is the purpose of each table.
If you have any questions or some of my code does not work, please tell me in the comments of this answer so I can help you work it out.
Edit:
After you have followed my steps and changed everything to English and modified the database, this is my new code:
First, edit ProductSalesOrder and add this method:
public function sales_order()
{
return $this->belongsTo(SalesOrder::class);
}
This will allow us to use relations of relations.
Then, have WorkOrder as my code:
public function sales_order()
{
return $this->query()->with('product_sales_order.sales_order')->first();
}
first should get you a ProductSalesOrder, but then you can access ->sales_order and that will be a model.
Remember that if any of this does not work, change all the names to camelCase instead of kebab_case.
I am using a left join to combine two tables based on a common column but I seem to lose the primary key id in my left table. Every other column is returned
My controller:
$prod_manu = $request->prod_manu;
return $data = Product::leftJoin('manufacturers','products.Manufacturer_id','=','manufacturers.id')
->where('products.Manufacturer_id',$prod_manu)
->get();
Product Model:
class Product extends Model{
public function types(){
return $this->belongsTo('App\types','Type_id');
}
public function manufacturers(){
return $this->belongsTo('App\manufacturers','Manufacturer_id');
}
}
This is probably because both Product and manufacturers have an id column, so one of them gets overwritten.
Instead of using the left join, you can use eloquent's with method.
If you have your relationships and class structure setup properly you should be able to access the Manufacturer's products like this:
$manufacturer = Manufacturer::where('id', $prod_manu)->with('products')->get();
return $manufacturer->products;
Also note that class names should always be singular and start with a capital letter in laravel. App\manufacturers Shouldn't be valid. Please read the article I linked above about setting up your eloquent relationships.
I am looking to pull data for related products correctly with the YII framework, as Im only learning this framework Im wondering have you advice on how I should go about this.
Ive taken over a project which uses YII, and it seems to have already some functionality in place, but I dont know how to utilize it.
Here is my current code...
In my Product model I have written this myself..
public function getRelatedProducts($id)
{
$rawData=Yii::app()->db->createCommand('SELECT * FROM '.Product::model()->tableName().' as Product LEFT JOIN '.ProductRelated::model()->tableName().' as ProductRelated ON ProductRelated.related_id=Product.id LEFT JOIN '.Images::model()->tableName().' as image ON Product.image_id=image.id WHERE ProductRelated.product_id='.$id.' ')->queryAll();
return $rawData;
}
and I get this data using...
$related_products = Product::GetRelatedProducts($model->id);
This works but is not using the YII framework.
I have noticed there is a model called ProductRelated (with not much in it).But I am not sure how to use it.
This obviously refers to a table I have in the database called product_related, which has 2 fields, product_id and related_id, where related_id represents the id of the product to which it was assigned(related to).
I would like to use this class as it was obviously written with this in mind. Right now Im just skipping over it.
class ProductRelated extends BaseProductRelated {
public static function model($className=__CLASS__)
{
return parent::model($className);
}
public static function LoadByProductIdRelatedId($intProductId , $intRelatedId)
{
return ProductRelated::model()->findByAttributes(array('product_id'=>$intProductId,'related_id'=>$intRelatedId));
}
}
Having read up some more about YII I have rebuilt my query...
public function getRelatedProducts($id)
{
$criteria = new CDbCriteria();
$criteria->alias = 'Product';
$criteria->join ='LEFT JOIN '.ProductRelated::model()->tableName().' as ProductRelated ON ProductRelated.related_id=Product.id';
$criteria->join .=' LEFT JOIN '.Images::model()->tableName().' as image ON Product.image_id=image.id';
$criteria->condition = 'ProductRelated.product_id='.$id.'';
$criteria->order = 'Product.id DESC';
return $criteria;
}
However I am not sure what to do with that final bit of code and how to link it up with the model I have shown above.
there are many mistakes in your code. I don't think your predecessor known yii very well too.
There are included functionalities to get relations.
read about yii relational active records:
http://www.yiiframework.com/doc/guide/1.1/en/database.arr
Best regards
Yii model uses the ActiveRecord pattern. You'll find that the relations() method of your model allows you to define relational data.
If your Product.relations() method is properly set, then the related products shall be 'magically' available.
NB : I guess the relatedProduct table is an association table for a n-n relationship between Product and... Product so you will use MANY_MANY. Take a look at the sample code at the end of the documentation of the relations() method.
I am using CodeIgniter
I have two tables -
Company
int id ,
varchar name
Employee int id, varchar name , int company_id
I have a simple controller called Employees Controller
<?php
class Employees extends CI_Controller {
public function index()
{
----
----
$data['employees'] = $selected_employees;
$this->load->view('employees/index',$data);
}
}
This controller passes an array of Employees to the view .
So inside my view , I can freely use employees[4].name , employees[3].id etc
Now If I want to show the name of the Company of the employees , it seems the only way is the Controller should pass another array with the name of the companies to the view . Is there any better way to achieve this - so that the controller doesnt have to explicitly have to send the data ?
For eg - say I want to access employees[4].company.name
I have been spoilt by Rails . I used to take these for granted .
The best way to go about this is using a join statement in your SQL query. The SQL query would typically look something like the following:
SELECT * FROM Employee JOIN Company ON Employee.company_id = Company.id
However, CodeIgniter's active record class will help us to simplify this (see http://ellislab.com/codeigniter/user-guide/database/active_record.html). In your model, you could write your query like so:
$this->db->select('*');
$this->db->from('Employee');
$this->db->join('Company', 'Employee.company_id = Company.id');
$query = $this->db->get();
You can tweak this to select the exact data that you want like you would any SQL query:
$this->db->select('Employee.id, Employee.name, Employee.company_id, Company.name AS company_name');
You can also add left, right, outer, inner, left outer, or right outer as a third parameter to the $this->db->join() function to allow for left joins, right joins, etc.
I would recommend using the Active Record class when possible in your CodeIgniter applications. It will help keep your queries clean, organized, and readable.
Do a join on your model
public function get_ selected_employees(){
$this->db->select('Employee.*, Company.name as company_name');
$this->db->from('Employee');
$this->db->join('Company', 'Employee.company_id = Company.id');
return $this->db->get()->result();
}
To get the company name just do employees[4].company_name
Two models are returned as Zend_Db_Select objects.
Then, I need to join them and fetch data together at once.
class Model_User extends Abstract_Model {
public function sqlUser() {
return $this->select(array(
'user_id', 'user.name', 'user.login', 'address.street', 'city.city_id', 'city.city_name','region.region_id', 'region.region_name'
))
->joinUsing('address','address_id','') ->join('city', 'city.city_id = address.city_id', '')
->join('region', 'region.region_id = city.region_id', '');
}
}
class Model_Technics extends Abstract_Model{
public function sqlList() {
return $this->select()
// here some more sql
->joinUsing('catalog_model','model_id','');
}
}
Then I need some where else fetch sqlList with all info for every user. I dont whant to duplicate all code, I just want to join sql from User model through join
You could iterate through the "sections" of zend_db_select (columns,from,joins,where) and figure a way to append them to the other query, but I wouldn't suggest it.
An alternative might be to have a "join" method on the model you're joining to, which will take your select object and run the join method(s) on it. It would, of course, depend on the table(s) already available in the select object already. Or that method might just pass back a structure defining how to join to the join-model's table, which your primary model can decide what to do with it.
There are a ton of solutions, but there's no really easy way to just jam two zend_db_select objects together without some extra logic between them. The main missing piece would be relationship information between the two models.
I know this isn't a full blown answer (as I can't comment yet), but hopefully it will point you to a path that sounds usable.