I want to show the names of all our project leaders in a dropdown list.
The project leaders are only some of the employees that work in the company.
Here are my tables:
project_leaders
,----,----------------,
| id | hr_employee_id |
|----|----------------|
| 1 | 18 |
'----'----------------'
projects
,----,------,-------------------,
| id | name | project_leader_id |
|----|------|-------------------|
| 1 | cake | 1 |
'----'------'-------------------'
hr_employees
,----,------,---------,
| id | name | surname |
|----|------|---------|
| 18 | joe | dirt |
'----'------'---------'
My ProjectsController looks like this:
public function add() {
if ($this->request->is('post')) {
$this->Project->create();
if ($this->Project->save($this->request->data)) {
$this->_sendProjectRequestEmail($this->Project->getLastInsertID() );
$this->Session->setFlash(__('The project has been saved'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The project could not be saved. Please, try again.'));
}
}
$this->set('projectLeaders',$this->Project->ProjectLeader->find('list');
}
This only returns the id of the Project Leaders, not the name and surname. So instead of Joe Dirt, it returns 1.
I've tried doing $this->Project->ProjectLeader->HrEmployee->find('list') but that lists all the employees.
I've also tried specifying the fields, but it returns a unknown field error.
What am I doing wrong?
$this->set('projectLeaders',$this->Project->ProjectLeader->find('list'));
This will just list the records from the project_leaders table and most likely, as the table doesn't itself contain a name/title field (which cake would pick up automatically as the displayField) be like so:
array(
1 => 1
)
Use an appropriate find
To get a meaningful list of project leaders, you need to ensure you get a join between project_leaders and hr_employees one way to do that is using the containable behavior and simply specifying which fields to use in the list:
$projectLeaders = $this->Project->ProjectLeader->find('list', array(
'contain' => array(
'HrEmployee'
),
'fields' => array(
'ProjectLeader.id',
'HrEmployee.name',
)
));
$this->set(compact('projectLeaders'));
Is your db structure appropriate for your needs?
Having a table equivalent to saying "this user is admin" may not be the best idea - it would be easier to avoid data problems, and give you simpler queries, if the table project_leaders was (only) a boolean field on your hr_employees table and project_leader_id pointed at the hr_employee table, not some other data-abstraction.
Of course I don't know your whole schema, there very well may be a good reason for having a seperate project_leaders table.
Alternatively - denormalize
If you add a name field to project_leaders - you don't need a join to know the name of a project leader or any funkiness:
alter table project_leaders add name varchar(255) after id;
update project_leaders set name = (select name from hr_employees where hr_employees.id = hr_employee_id);
In this way you can know who is the relevant project lead with one query/join instead of needing to do two joins to get an employee's name.
You forgot to define the displayField:
The default case is
public $displayField = 'name';
And only for an existing "name"/"title" field in this table cake will automatically know what your drop-downs should get as label text.
To use the fields of other tables, make sure you pass fields in your find() options:
'fields' => array('Project.id', 'Project.name');
etc. Cake will then know: the first one is the key, and the second one the display value.
If you need combined/custom fields/texts in your dropdowns use virtualFields
public $virtualFields = array(
'full_name' => 'CONCAT(...)'
);
and set the displayField to this full_name virtual field then or use fields as explained above.
You could add a virtual field to your ProjectLeader Model:
public $virtualFields = array (
'name' => 'SELECT name FROM hr_employees AS Employee WHERE Employee.id = ProjectLeader.employee_id'
);
Also, add this virtual field as your displayField:
public $displayField = 'name';
Related
Im working in a octobercms plugin and i have the following models in it:
Houses
Pays
Owners
In Houses model i have the following relationship:
public $hasManyThrough = [
'owner' => [
'Author\Plugin\Models\Owner',
'table' => 'author_plugin_houses_owners',
'key' => 'houses_id',
'otherKey' => 'owners_id'
]
];
this relationship has a intermediate table 'author_plugin_houses_owners':
+------------+-------------+--------+
| hoses_id | owners_id | active |
+------------+-------------+--------+
And in Pays model i have the following relationship:
public $belongsTo = [
'houses' => ['Author\Plugin\Models\Houses']
];
this model corresponds to a table like this:
+----+----------+---------+-------+------+
| id | hoses_id | amounth | payed | debt |
+----+----------+---------+-------+------+
in the table i have a column "houses_id", the question is, how i can access to "owner" relationship declared in "Houses" model since "Pays" model? i need access to it because i need printed "owner_name" on list view in the plugin backend.
owner table:
+----+------------+--------+
| id | owner_name | active |
+----+------------+--------+
thanks a lot!
I assume that Pay belongs to only one house.
public $belongsTo = [
'house' => ['Author\Plugin\Models\Houses']
// ^ you can use house instead houses for relation name
];
Now we can access owner with relation chain
$payModel->house->owner
Since you made relation hasMany one house can have multiple owners [ hasManyThrough ]
so this will return you a list of owners.
As in list view you need to use it, You can define partial type column
columns:
id:
label: id
type: number
searchable: true
sortable: true
.... other fields ...
owner_name:
label: Owner
type: partial
path: $/hardiksatasiya/demotest/models/sort/_ownername_column.htm
Make sure to replace the path with your own plugin author name and path.
Now inside partial, you can write your actual logic [ this must be in PHP not in twig ]
<?php
// this is hasmany relation so we expect multiple owners
$owners = $record->house->owner;
$ownerArr = [];
foreach($owners as $ownr) {
$ownerArr[] = $ownr->owner_name;
}
$output = implode($ownerArr, ', ');
?>
<?php echo $output ?>
If there is only one owner it will show Hardik one name only if there are multiple owners it will show Hardik, Noe comma separated values.
if any doubts please comment.
I have two related tables. One of the table has a one to many relationship to the second table. This is a sample illustration of the two tables
**
registration
id | firstname | membershipfk
1 | John | 2
2 | Foo | 3
**
Here is illustration of the second table
membership
id | type | discount | description
1 | Gold | xyz | xyz description
2 | Silver | xyz | xyz description
Now my present challenge is to retrieve the membership fields from the membership table using the foreign key in the registration table.
For example: Select Type, Discount and Description from Membership Entity where fk in registration entity is equal to 2
Presently in my controller I am making this attempt
public function getMembersAction()
{
$restresults = $this->getDoctrine()->getRepository('XXXBundle:Members')->findAll();
$data = array();
foreach ($restresults as $restresult) {
array_push($data, $this->serializeData($restresult));
}
Every kind assistance is much appreciated
Try with the following code
$em->getRepository('XXXBundle:Members')
->createQueryBuilder('m')
->select("m.type, m.discount, m.description")
->innerJoin("XXXBundle:Registration","r","WITH","m.id = r.membershipfk") //Here you will Join with the Registration Bundle
->where("m.id = 2")
->getQuery()
->getResults();
you need to call a findBy for example if your entity are set well.
Try this:
$results = $this->getDoctrine()->getRepository('XXXBundle:Members')->findByMember($memberId);
But you need to have configured well your entity first
For simplicity sake, I have simplified my tables to get my core need across.
I have two tables: admins and users. The admin table simple holds certain information that is not entirely relevant to the question.
Admins:
+----+---------+
| id | user_id |
+----+---------+
| 1 | 20 |
+----+---------+
| 2 | 25 |
+----+---------+
| 3 | 27 |
+----+---------+
Users:
+----+--------+-----------+
| id | name | surname |
+----+--------+-----------+
| 20 | Name 1 | Surname 1 |
+----+--------+-----------+
| 25 | Name 2 | Surname 2 |
+----+--------+-----------+
| 27 | Name 3 | Surname 3 |
+----+--------+-----------+
The idea is that when a super admin saves a new user, the fill in a form, being a user registration for of sorts and upon saving it saves the user and creates the admin record with the newly created user id.
Obviously the admin record cannot be created without the user account existing as it requires the user id. Cake simple returns an error saying "user_id is required".
This is my form:
<?= $this->Form->create($user) ?>
<fieldset>
<legend><?= __('Add Admin') ?></legend>
<?php
echo $this->Form->input('user.name');
echo $this->Form->input('user.surname');
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
I have tried creating a user with an admin association and the other way around:
$admin = $this->Admins->newEntity();
if($this->request->is('post')) {
$this->Admins->patchEntity($admin, $this->request->data,[
'associated' => ['Users']
]);
$savedAdmin = $this->Admins->save($admin);
}
and
$user = $this->Admins->Users->newEntity();
if($this->request->is('post')) {
$this->Admins->Users->patchEntity($user, $this->request->data,[
'associated' => ['Admins']
]);
$savedUser = $this->Admins->Users->save($user);
}
I do not what to save separate entities because I know it is possible to saved associated data, I'm just not really how to saved the admin record as it relies on the user record.
It sounds like it might make more sense to have a boolean field in the user table that defines whether a user is an admin or not.
That being said, you may need to define the relationship in your models if it is not there already. Technically, based on your table names and and columns (user_id) Cake should bake this in for you, but I don't remember if it's conventional to have plural model names (Users, Admins), so this may not have happened.
User:
public $belongsTo = [
'Admins' => [
'classname' => 'Admins', //are your models really plural?
'foreignKey' => 'user_id',
];
Admin
public $hasOne= [
'Users' => [
'classname' => 'Users',
'foreignKey' => 'user_id',
];
Then, I think you'd need to specify some information about the admin, or you won't have any data to save the association. In the view:
echo $this->Form->input('admins.field1');
echo $this->Form->input('admins.field2');
echo $this->Form->input('admins.field3');
Note these fields can be hidden if you don't want anything inputted.
To save, make a new user from the request data (your form creates a user, but you could create an admin with the form, and then add inputs like user.name and user.surname). Controller:
$user = $this->Admins->Users->newEntity();
if($this->request->is('post')) {
$this->Admins->Users->patchEntity($user, $this->request->data, [
'associated' => ['Admins']
]);
$this->Admins->Users->save($user);
}
First, create your admin entity and then associate users (as admin requires the user id). Once you have done that create your new user entity and assign it to a variable.
The, manually assign the foreign key the newly created user, and Cake will figure out it needs to assign it the primary based on your model. Finally, save your admin, and it will automatically save your associated entity.
That's why it is important to define your belongs to and has one in the relevant models as mentioned in the previous answer.
if ($this->request->is('post')) {
$admin = $this->Admins->newEntity($this->request->data, [
'associated' => ['Users']
]);
$user = $this->Admins->Users->newEntity();
$admin->user_id = [$user];
$saved = $this->Admins->save($admin);
}
can anybody help me on the following query.
I have a table that holds a postcode column and a rating column, ie.
ID | POSTCODE | RATING
1 | sk101dd | E
2 | sk101de | A
3 | sk101df | E
4 | sk101dg | E
5 | sk101dh | D
etc
This is set up as a model called PostcodeList
I have a relational table, linked via the RATING column that holds a customer id and cost, ie.
ID | CUSTOMER_ID | RATING | COST
1 | 1234 | E | 0.05
2 | 9999 | E | 0.02
This is set up as a model called RatingCost. I linked this to PostcodeList model using the following code:
public function costing()
{
return $this->hasMany('PostcodeList','RATING','RATING');
}
I need to return the COST from the RatingCost model using CUSTOMER_ID as the filter without resorting to multiple sql statements. I think I've nearly got it, using the code below, but it's not quite right:
$p = PostcodeList::where('postcode',$somepostcode)->first();
$cost = $p->costing()->where('customer_id',$somecustomerid)->first()->cost;
The error I'm getting at the moment is "Trying to get property of non-object".
Any help greatly appreciated. I don't want to resort to DBRAW or another form of join as I really like the relational setup Laravel provides.
thanks
I know you're trying to stay away from joins, but this Laravel query would produce the desired results:
DB::table('PostcodeList')
->join('RatingCost', function($join)
{
$join->on('RATING', '=', 'RatingCost.RATING')
->->where('customer_id',$somecustomerid)
})
You have this
$postcode_get = PostcodeList::where('postcode',$somepostcode)->get();
foreach($postcode_get as $p){
...
$cost = $p->costing()->where('customer_id',$somecustomerid)
// ...
}
You have defined the method costing in your RatingCost model but calling it from PostcodeList model, in this case you need to declare the relation inside your PostcodeList model like this:
public function costing()
{
// change the field name 'RATING' in any table, maybe
// prefix with table name or something else, keep different
return $this->belongsToMany('RatingCost','RATING', 'RATING');
}
So, you can use this (inside loop):
$cost = $p->costing();
Because, inside your loop each $p represents a PostcodeList model and $postcode_get is a collection of PostcodeList models.
I don't think what I'm trying to do is actually possible without using joins. So the solution was to scrap the belongsTo and hasMany options for a standard join (similar to dev_feed's response):
$pr = PostcodeList::join('RatingCost', function($join)
{
$join->on('PostcodeList.content_rate', '=', 'RatingCost.code');
})
->where('postcode', '=', $somepostcode)
->where('RatingCost.customer_id','=',$somecustomerid)
->first();
I'm trying to create a system more dynamic for my users, implementing a way of they create each necessary information when they needed. (Sorry if my english is weak)
First, I have a table named User, like this:
User:
id | name | login | password
1 | Rose | rose.120 | 897763
2 | John | john.red | 120347
3 | Mark | mark.foo | 385598
and the other table with some info of each user:
User_info:
id | user_id | info_name | value | required | order
6 | 1 | Telephone | 555-4083 | yes | 2
7 | 1 | Email | rose.120#g.com | yes | 1
8 | 1 | Another E-mail | rose.mg#fc.com | no | 3
When I get this values from the database, how make an efficient way to set a PHP Object, or an Array of this values.
I tried to make a mysql_query and with this result make a loop in the Object, and for any Row make a WHERE clause to the user id. (I'm using CodeIgniter)
if( $user != false ) $this->getUser();
foreach( $this->user->result() as $row ) {
$this->db->where('user_id', $row->id);
}
$this->db->from('user_info');
...
and when I have this Object I will need to put the User_info rows in the User Object. Correct?
I'm just curious if this is a good way of doing this, or I'm in the wrong way.
I hope that's clear.
Thanks.
Basically, yes. You could set up your model to define a method for retrieving information from both your user_info and user tables, however. Something along these lines:
// in user_model.php
function get_user_with_info() {
$user = $this->getUser();
$user['info'] = $this->db->where('user_id', $row->id)->from('user_info')->row();
return $user;
}
If you are planning to make this query often, you will quickly run into the N+1 problem. A better option in Codeigniter might be to use a table join in a get_users function:
function get_users() {
$this->db->select('*')
$this->db->from('user');
$this->db->join('user_info', 'user.id = user_info.user_id');
$results = $this->db->result();
$users = [];
foreach ($results as $result) {
$user_id = $result['user_id'];
if (!isset($users[$user_id])) {
$users[$user_id] = array(
'id' => $user_id,
'info' => array(
// add info fields from first result
)
);
} else {
$users[$user_id]['info'][] = array(
// add additional info fields
);
}
}
return $users;
}
You will need to adjust the specifics, but hopefully this gives somewhere to start.
Don't forget, in this way you must working with dynamic arrays in user object. Instead of fields named as "Telephone", "Email" and other, which you can access as $user->Telephone, $user->Email and other (this is a simple and I think a good way), you must create dynamic array with pairs $info_name->$value. And in "User" object you must create additional functionality, which parse each property $info_name. This is more flexible, but more complex.
So I think, you must find golden mean for you between flexibility and complexity.
While using code codeIgniter, make a function in your model file and put your code. Then, in the controller, call this function in the model and send your required parameter. You are using codeigniter then you have to follow the architecture too.