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
Related
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.
For example:
Query
SELECT book.\*,author.* FROM book
INNER JOIN author ON author.id = book.author_id
WHERE book.id=1
Get model
$modelBook = Book::find()->innerJoin('author','author.id = book.author_id')->where(['book.id'=>1])->one();
$modelAuthor = Author::findOne(['id'=>$modelBook->author_id]);
The problem:
How can I get 2 activerecord model Book and Author with just only one mysql execute?
I know that we can use with() function, but it spend another query SELECT ...IN(...) to get second model, although we have sufficient data from join query
Is there a more effective solution ?
ActiveRecord are for model extendinng the ActiveRecord classe
You seems are using a query and not a "model" so i suggest you of use activeDataProvider.
You can refer the models managed by dataProvider using getModels() function
$provider = new SqlDataProvider([
......
]);
// returns an array of data rows
$models = $provider->getModels();
see this guide and reference for detail
http://www.yiiframework.com/doc-2.0/guide-output-data-providers.html
http://www.yiiframework.com/doc-2.0/yii-data-sqldataprovider.html
Try this :
With approach is not slower in case of performance.
$modelBook = Book::find()->with('YOUR_RELATION_NAME_HERE')->findByPK(id);
I've been using the Fat-Free Framework recently, and things are going well (arguably better the longer I use it and leverage its components); however, I'm having difficulty with the ORM injecting the MySQL table name into a virtual field (used for lookup).
I know the SQL is good, and I know I could perform a second database call to retrieve the lookup field data, but since I've got things nearly working in virtual field format (and it's probably easiest to digest and debug)...
Is there any way to prevent F3 from inserting the table name during SQL generation?
Setup is easy...
class Bookmark extends \DB\SQL\Mapper
In the constructor, after the call to the parent constructor, I add my virtual fields...
$this->type_name = '
SELECT CASE bookmark_type_id
WHEN 1 THEN \'Project\'
WHEN 2 THEN \'Member\'
ELSE \'Unknown\' END
';
NOTE: This works, though NOT if I use an IF, then I get the table name injected into the IF clause -- after the first comma.
$this->description = '
SELECT CASE bookmark_type_id
WHEN 1 THEN (SELECT p.title FROM projects p WHERE p.id = reference_id)
WHEN 2 THEN (SELECT CONCAT_WS(\' \', m.first_name, m.last_name) FROM members m WHERE m.id = reference_id)
ELSE \'Unknown\' END
';
NOTE: This fails with the table name inserted after the first comma (i.e. before m.first_name).
For clarity, this is the result (notice `cm_bookmark`.):
SELECT CASE bookmark_type_id
WHEN 1 THEN (SELECT p.title FROM projects p WHERE p.id = reference_id)
WHEN 2 THEN (SELECT CONCAT_WS(' ',`cm_bookmark`. m.first_name, m.last_name) AS FullName FROM members m WHERE m.id = reference_id)
ELSE 'Unknown' END
) AS `description`
I get the feeling this is just another one of those "don't do that" situations, but any thoughts on how to achieve this in F3 would be appreciated.
(Oddly, it's only after the first comma in the subquery. If the table name insertion was consistently clever, I'd expect to see it peppered in front of m.last_name too, but it isn't.)
EDIT: It seems as though it's related to the second occurrence of something in parentheses. I've used CONCAT() in another virtual field call, and it works fine -- but it's the first (and only) use of parentheses in the field set up. If I remove the call to CONCAT_WS() and return a single field, the setup above works fine.
EDIT2: To clarify how the load is occurring, see below...
// database setup
// (DB_* set up in config.ini)
$db = new \DB\SQL($f3->get('DB_CONN'), $f3->get('DB_USER'), $f3->get('DB_PASS'));
$f3->set('DB', $db);
...
// Actual call
$db = \Base::instance()->get('DB');
$bookmark = new \CM\Models\Bookmark($db);
$bookmark->load_by_id($item['id']);
...
// in Bookmark Class (i.e. load_by_id)
$b->load(array('id=?', $id));
The only answer (to stay on this path) I have come up with so far is to create another virtual field and piece the 2 parts together later.
Not ideal, but it works.
The mapper does not allow such advanced capabilities, but I would suggest you use Cortex which luckily extends mapper so not much code change.
Below is an example:
Class Bookmark extends \DB\Cortex{
protected
$db = 'DB', // From $f3->set('DB', $db);
$table = 'bookmarks'; // your table name
/* You can also define these custom field preprocessors as a method within the class, named set_* or get_*, where * is the name of your field.*/
public function get_desciption($value) {
switch($this->bookmark_type_id){
case "1":
/*.....................Hope you get the drill*/
}
}
}
I'm using the default Authentication system that Laravel provides. However, I want to join two tables (perform two inner joins) on my Auth table (users). So far, I have created two relationships between two models and this works fine and gets me the data I want, however it performs two extra queries when I think in hindsight doing two joins on the table would be much more efficient.
What I don't know how to do is to perform the Joins on the User Model so that I'm not having to create a new query (but rather use the one that is created by calling Auth::user()).
My tables:
Users: id username iconid avatarid
Icons: id image
Avatars: id image
So what I'd like to do is:
SELECT icons.image as icon_image, avatars.image as avatar_image FROM users
LEFT OUTER JOIN icons ON icons.id = users.iconid
LEFT OUTER JOIN avatars ON avatars.id = users.avatarid
Is this possible? Do I just need to overwrite a method in my User model in order for Auth::user() to run the above query?
Thank you to anyone who replies!
Put this in your user model:
public function icon()
{
return $this->hasOne('Icon');
}
public function avatar()
{
return $this->hasOne('Avatar');
}
Then get the user like this:
$user = User::with(['icon', 'avatar'])->find(1);
Then you can access the icon and avatar like this:
$user->icon
$user->avatar
To do this with joins you can do this:
$user_id = 1;
DB::table('users')
->join('icons', 'icons.id', '=', 'users.icon_id')
->join('avatars', 'avatars.id', '=', 'users.avatar_id')
->select('users.name', 'icons.path', 'avatars.path')
->where('users.id', $user_id)
->first();
I am attempting to pull a list of users using doctrine, with a join, from my database. I have the following function in my model:
public function getAttendees() {
$q = Doctrine_Query::create()
->select('a.id, a.name, a.url, m.id')
->from('Attendees a')
->leftJoin('a.Meetings m WITH m.Meeting_Slot_ID = ?', $this->getId());
return $q->execute();
}
I've checked the SQL generated by this query, and it is gabbing all the data I want. I am now trying to access the data retrieved. I have the following working:
foreach($object0>getAttendees() as $attendee){
echo $attendee->getName();
}
However, I can't figure out how to access the m.id field.
I think you can do this:
$attendee->getMeetings()->getId()
You have to use the alias you defined in your schema.yml (if you are using symfony)
Generally Doctrine uses this way to chain related models together:
model1->model2->model3
...->getModel2()->getModel3()->getModel3Field()
$attendee->getMeeting()->getId(); OR soemthing to that effect depending on how you have your relations/properties named.