I need help constructing a CodeIgniter Datamapper ORM query that includes join fields.
I have a table of Merchants and a table of Vendors.
They have a many-to-one relationship, that is, many Merchants are part of a single Vendor.
Thus, my datebase tables, following the Datamapper ORM convention are:
merchants
vendors
merchants_vendors
Furthermore, in the merchants_vendors table, I have join fields 'role' and 'admin'.
Obviously, this data must be placed in the join table, if it were placed in the Merchants table, I wouldn't be able to define roles and administrators per Vendor.
Lastly, Merchants are related to Users by a one-to-one relationship.
Think of Merchants as just an extension of Users.
I'm attempting to create a PHP array from the data that follows this data structure, but I can't seem to get the role and admin fields populating properly. I removed redundant columns for your simplicity:
[vendor] => Array
(
[id] => 1
[name] => Vendor1
[users] => Array
(
[0] => Array
(
[id] => 277
[username] => merchant1
[firstname] => Merchant1
[merchant] => Array
(
[id] => 1
[user_id] => 277
[role] => Sales
[admin] => 0
)
)
[1] => Array
(
[id] => 282
[username] => merchant2
[firstname] => Merchant2
[merchant] => Array
(
[id] => 2
[user_id] => 282
[role] => Software
[admin] => 1
)
)
)
)
Here's the code I'm using - Assuming we know the Vendor ID:
$v = new Vendor($id);
if($v->exists())
{
$d['vendor'] = $v->to_array();
$m = new Merchant();
$m->where_related_vendor('id', $v->id)->get();
if($m->exists())
{
foreach($m as $mK => $mV)
{
$u = new User();
$u->where_related_merchant('id', $mV->id)->get();
$d['vendor']['users'][$mK] = $u->to_array();
$d['vendor']['users'][$mK]['merchant'] = $mV->to_array();
}
}
}
$this->load->view('myview', $d);
This gets me as far as the above PHP data structure without the role and admin.
I am well aware of the include_join_fields() function - but I cannot seem to get it working. Specifically, I tried $m->vendor->include_join_fields(); Then tried to access the role/admin fields by $mV->vendor->join_role and $mV->vendor->join_admin - but that doesn't work.
Your help is much appreciated!
The solution was to use include_join_fields() on the $mV object inside the forloop:
$v = new Vendor($id);
if($v->exists())
{
$d['vendor'] = $v->to_array();
$m = new Merchant();
$m->where_related_vendor('id', $v->id)->get();
if($m->exists())
{
foreach($m as $mK => $mV)
{
$u = new User();
$u->where_related_merchant('id', $mV->id)->get();
$mV->vendor->where('id', $v->id)->include_join_fields();
$d['vendor']['users'][$mK] = $u->to_array();
$d['vendor']['users'][$mK]['merchant'] = $mV->to_array();
$d['vendor']['users'][$mK]['merchant']['role'] = $mV->vendor->join_role;
$d['vendor']['users'][$mK]['merchant']['admin'] = $mV->vendor->join_admin;
}
}
}
$this->load->view('myview', $d);
Ongoing discussion in the CodeIgniter forums.
I will post more information as it arrives.
include_join_fields() doesn't execute anything, it just sets a flag that you want these fields included.
Both examples above miss the get() that actually executes the query...
Related
I have model for
user(id,name)
section(id,name)
section_users(id,user_id,section_id)
The admin adds all the users and sections separately. Once theses are added I want the admin to selects the section and add all the users in it in section_users
I have a select input with multiple set to true. How do i save this data the cakephp way along with validation.
<?php echo $this->Form->input("section_id"); ?>
<?php echo $this->Form->input("user_id", array('multiple'=>'checkbox')); ?>
This generates
Array
(
[section_id] => 1
[user_id] => Array
(
[0] => 3
[1] => 4
)
)
I know i can loop and convert to this and use saveAll or saveMany but what is the cakephp way/right way to do it.
Array
(
[0] => Array
(
[section_id] => 1
[user_id] => 3
)
[1] => Array
(
[section_id] => 1
[user_id] => 4
)
)
As already mentioned, this is exaplained in the docs, please read them, and in case you don't understand them (which would be understandable as the HABTM section is a little confusing and requires some trial & error), tell us what exactly you are having problems with.
http://book.cakephp.org/2.0/en/models/saving-your-data.html#saving-related-model-data-habtm
Based on the examples shown, the format for saving multiple X to Y should be
Array
(
[Section] => Array
(
[id] => 1
)
[User] => Array
(
[User] => Array(3, 4)
)
)
The corresponding form could look like this:
<?php echo $this->Form->create('User'); ?>
<?php echo $this->Form->input('Section.id'); ?>
<?php echo $this->Form->input('User', array('multiple' => 'checkbox')); ?>
<?php echo $this->Form->end('Add Users'); ?>
And the data would be saved via the Section model, that way its modified column is being updated properly.
public function addUsersToSection($id) {
// ...
if($this->request->is('post')) {
if($this->Section->save($this->request->data)) {
// ...
} else {
// ...
}
} else {
$options = array(
'conditions' => array(
'Section.' . $this->Section->primaryKey => $id
)
);
$this->request->data = $this->Section->find('first', $options);
}
$users = $this->Section->User->find('list');
$this->set(compact('users'));
}
Another way would be to restructure the array as shown by Vinay Aggarwal, that works fine, the only difference is that it requires saving through the join model, and consequently it doesn't update the Section models modified column.
CakePHP has the saveMany function, as mentioned in the documentation:
Model::saveMany(array $data = null, array $options = array())¶
This is HABTM relation, first of all you need have relation setup in SectionUser model. Then you can use saveAll() method to save all records at once.
Array
(
[0] => Array
(
[user_id] => 33
[section_id] => 9
)
[1] => Array
(
[user_id] => 33
[section_id] => 10
)
)
Make sure your data array is in above given format.
$this->SectionUser->saveAll($data);
I am creating a helper function to get name field value from user group array. So whole idea is to pass value in function parameter like system_admin and than will pass in switch to get content according to the user group defined.
Till now I have done as below. I'm sure done is crappy way but no idea how to make it work.
Function
function admin_heading($groupname)
{
$CI =& get_instance();
$groups = $CI->ion_auth->groups()->result();
foreach ($groups as $key => $value)
{
foreach ($value as $val => $result){
echo $result . '<br/>';
}
}
//return $groups;
}
If I return $group than getting this Array
Array
(
[0] => stdClass Object
(
[id] => 1
[name] => system_admin
[description] => System Administrator
)
[1] => stdClass Object
(
[id] => 2
[name] => admin
[description] => Administrator
)
[2] => stdClass Object
(
[id] => 3
[name] => HR
[description] => Human Resources
)
[3] => stdClass Object
(
[id] => 4
[name] => REC
[description] => Recruitment
)
[4] => stdClass Object
(
[id] => 5
[name] => TRA
[description] => Training
)
[5] => stdClass Object
(
[id] => 6
[name] => AMs
[description] => Account Managers
)
[6] => stdClass Object
(
[id] => 7
[name] => TLs
[description] => Team Leaders
)
[7] => stdClass Object
(
[id] => 8
[name] => FIN
[description] => Finance
)
[8] => stdClass Object
(
[id] => 9
[name] => FAC
[description] => Facilities
)
[9] => stdClass Object
(
[id] => 10
[name] => AHT
[description] => After Hours Transportation
)
[10] => stdClass Object
(
[id] => 11
[name] => member
[description] => Member
)
)
By echoing $result getting below result
1
system_admin
System Administrator
2
admin
Administrator
3
HR
Human Resources
4
REC
Recruitment
5
TRA
Training
6
AMs
Account Managers
7
TLs
Team Leaders
8
FIN
Finance
9
FAC
Facilities
10
AHT
After Hours Transportation
11
member
Member
1
So the final result I want is for instance
When I pass system_admin in function admin_heading('system_admin') that it will check if system_admin group exists in db. If exists than it will pass in switch($var) and I will have file with the group name which will be called base on it.
Now this type of conditional code doing first time so don't know if any better way than this. So if there is any better way please learn me. I would appreciate.
Edit
So what exactly I am looking for is
I want to load the file/content and heading as per the user group. So for example if logged in user is system_admin it will check group automatically and load file/content and heading accordingly same as for the other groups.
Note: User also may be in multiple groups so need to check the higher group and load content accordingly.
I hope this would be easy to understand.
I would suggest you should save rank as well in DB. It will help
if user having multiple access (e.g System Administrator, Administrator).
Create a separate function which will check usergroup and return user role.
<?php
function admin_heading($groupname) {
$userId = 101; // You can get login userid here.
$userRole = $this->checkUserRole($userId);
switch ($userRole) {
case 'administrator':
// Load heading for administrator.
break;
case 'hr':
// Load Heading for HR
break;
default:
// May ur default role :)
break;
}
}
function checkUserRole() {
$CI = & get_instance();
//$userRole = ''
// Run a single query which will return user max group.
return $userRole;
}
I suppose you are able to fetch user details and roles available in DB. So run a single query to
get user higher role, may be you need join user table with your role table.
I have a table named user. The id is generated on the fly.
I have a HABTM table. I am trying to insert a record during the user registration. For some reason I can't get the user's id and the user_id to match.
This looks correct, even my array reflects the right information, but the actual data stored is not right.
code:
$this->request->data['User']['id'] = String::uuid();
$this->request->data['Company']['Company'][0]['user_id'] = $this->request->data['User']['id'];
returned array:
Array
(
[User] => Array
(
[email_address] => asdf#asdf.com
[id] => 4fc9a939-3e24-4c79-85d1-6c28e4ca782d
)
[Company] => Array
(
[Company] => Array
(
[0] => Array
(
[id] => 4fc9a939-1840-4c1b-8bd2-6c28e4ca782d
[company_id] => 4fc990dd-edb0-4559-bb7b-6a00e4ca782d
[user_id] => 4fc9a939-3e24-4c79-85d1-6c28e4ca782d
)
)
)
)
So it appears that it would work based on the array I got, but it doesn't save like that. Help is much appreciated.
Maybe because cake autogenerates id to UUID (when field is string and length is 36) take a look at CakePHP API - Model->save()
I'm developing a simple application with CakePhp, and need some help on creating a multi-record edit form using some related data.
The application I'm developing is pretty straightforward, its main purpose is managing students records: updating, deleting, changing a student from one group to another, the usual suspects.
The relevant tables of the database are:
group = (id, teacher, classroom, etc)
groups_students=(groupID, studentID, since, until)
students = (id, name, last_name, etc)
assitance = (id, assitance, date)
assistance_students (studentID, assitanceID, meta_information )
As you might have gathered from the tables above, the application is supposed to aid in recording assitance. Which is where I'm having some issues.
What I want to do is this:
Have the user select a group
In de detail group, I'll have an action called "Register Assistance"
Register assitance should redirect to a view in wich for every student belonging to that group, the user can see the student's assitance, edit them, and save. Something like this:
In which A stands for "Absent" and P for "Present" and the user can edit everyone, and the save.
I just don't know how to go about that? How do I manage that? I've managed to create a multi-edit form for the assitance, but adding the related data is a pain, I don't know if I should query the students from the groups controllers and then pass that to the action to register assitance, or manage all the logic inside the assitance controller?
Any help would be great,
thanks!
Edit: Here's the output of $this->Student->find('first');
Array (
[Alumno] => Array (
[id] => 14
[tipo] => dni
[dni] => 2321312312
[apellido] => COQUITO
[nombre] => Pepe
[carrera] => Composición Musical
[creado] => 2011-01-08 17:59:00
[modificado] => 2011-01-08 17:59:00
)
)
The output is in spanish. Alumno = Student, nombre= first name, apellido= last_name.
Well, I managed to find a solution to this. I was waiting to see if anyone found something better, as I'm pretty sure my solution is far from the best, but here it goes, in case someone finds this question in the future.
My issue was that I needed, for every group I selected to register assitance:
Every student that belonged to that group
All the assitances of the students belonging to that group
Now, in order to make use of the Form helper to edit those assitences (and after, the saveAll() method), I needed $this->data to have ann array like this:
Array
(
[Assitance] => Array
(
[5] => Array
(
[id] => 5
[date] => 2011-01-09
[assitance] => A
[updated] => 2011-01-16 21:32:00
[created] => 2011-01-16 21:32:00
)
[6] => Array
(
[id] => 6
[date] => 2011-03-09
[assitance] => A
[updated] => 2011-01-16 21:32:00
[created] => 2011-01-16 21:32:00
)
)
)
at the same time, though, I needed each student linked to his or her assitances, to be able to loop trough them, and display the edit forms for every assitance in a table like the one in the question:
What I ended up doing is this
First, I query all the students belonging to the selected group.
For each student get all his/her assitances .
so, for each student, I ended up having an array like this:
Array
(
[Student] => Array
(
[id] => 12
[last_name] => LASARTE
[name] => Julia
[created] => 2011-01-08 16:35:00
[updated] => 2011-01-08 16:35:00
[assitance] => Array
(
[0] => Array
(
[Assitance] => Array
(
[id] => 4
[date] => 2011-01-09
[assitance] => z
[updated] => 2011-01-16 20:51:00
[created] => 2011-01-16 20:51:00
)
[assitance_studenty] => Array
(
[id] => 2
[student_id] => 12
[assitance_id] => 4
[comision] => 0
)
)
)
)
)
)
Now, with that, I have the information I need in order to display the table and create the forms, but I still need the assitances data in $this->data, so the form helper can create the from displaying the correct information, and afterwars, saveAll() updates the rows in the database correctly.
What I needed to do was turn the array of $students into an structure like the one at the beginning of the post. Enter the Set Class:
$formated_students = Set::combine($students, '{n}.students.id', '{n}.students');
$assitance = Set::extract('/presentes/Assistance', $formated_students);
$this->data['Assistance'] = Set::combine($assistance, '{n}.Assistance.id', '{n}.Assistance');
I'm pretty sure the first to lines (formating the students array in order to extract the assitance) can be done with just one Set::extract or Set::classicExtract, but this worked and regular expressions are really not my thing, so.
After that, It's just a matter of looping trough the data and making the table:
<?php
echo $form->create('Assistance', array('url' => array('controller' => 'Comisions', 'action' => 'register_assitance')));
foreach ($students as $student) { ?>
<tr><td>><?php echo $student['students']['last_name'].", ".$student['students']['name']; ?></td>
<?php foreach ($student['students']['assitance'] as $asstiance) { ?>
<td><?php echo $form->input('Assistance.'.$assitance['Assistance']['id'].'.id');
echo $form->input('Assistance.'.$assitance['Assistance']['id'].'.assistance', array( 'label' => false, 'size' => 1)) ?></td>
<?php } ?>
</tr>
<?php } ?>
I'm working on retrieving a stack of data and for some reason some of the data gets corrupted. For instance, I've got some Post models that each are related to Comment models (hasMany), and each of the Comment models belongsTo a User. When retrieving the data, here's what I get from the database for the comments:
[Post] => Array
(
)
[Comments] => Array
(
[0] => Array
(
[content] => "2010 has definitely been a busy year!"
[created] => 2010-02-10 13:47:15
[user_id] => 18
[post_id] => 1
[User] => Array
(
[id] => U8
[username] => Uace
[first_name] => Uace
)
[_explicitType] => Comment
)
[0] => Array
(
[content] => "I can't wait..."
[created] => 2009-12-10 13:57:36
[user_id] => 18
[post_id] => 1
[User] => Array
(
[id] => U8
[username] => Uace
[first_name] => Uace
)
[_explicitType] => Comment
)
)
The first character of each of the Comments[i][User] arrays has been replaced with a capital U, though in each case it should be different (such as ID of 18, username of Jace, etc).
I traced it back to an array manipulation I was working with to assign an _explicitType field for Flex interaction (Thanks, Paweł Mysior!) in the afterFind() function. Here's the loop where I stuck in the _explicitType:
if (is_array($results)) {
foreach ( $results as &$item )
{
$item['_explicitType'] = $this->name;
}
} else {
$item[$this->name]['_explicitType'] = $this->name;
}
I assume it has to do with the assignment by reference, but I can't think of why it is happening.
It is very strange.
Set debug to 2 in core.php and look in the sql log at the bottom of the page, maybe you'll find something there. Also look through all models (app, post, user, comment). There might be some beforeFind() that are causing this to happen. Does it also happen when you do a simple User->find()?
Btw. how do you retrieve data here?
I think found the issue. I moved the check for the array inside the foreach() and that seems to be working correctly now. I assume this is because on non-array items, it actually broke things. Here's my altered loop with logging on the test cases:
foreach ( $results as &$item )
{
if(is_array($item)) {
$item['_explicitType'] = $this->name;
} else {
$copy = $item;
$copy['_explicitType'] = $this->name;
$this->log($copy, LOG_DEBUG);
}
}
And sure enough, it logged the data with capital U's replacing the first letter.