Can I make two seemingly unrealated associations between two tables? - mysql

I am developing a resume app and have created a table called areas using the CakePHP Tree Behaviour. In this table, I have a bunch of countries and cities.
The original purpose of this table was to allow users to specify which areas they are interested in working in on their resume. This is pretty straightforward and I have created a HABTM relationship between users and areas to deal with this.
However, the next thing I need to do is allow users to specify where they are from. Of course, I could create a new table, identical to areas and call it something different, but this seems a bit wasteful and inefficient.
So, I am wondering if it is actually possible to have two totally different associations between the users table and the areas table?
In other words, the users table would have-and-belong-to-many areas (for the purpose of users specifying all of the areas they are interested in working in in the world) but it would also have-one area (for the purpose of users specifying which country they are from).
I can't begin to imagine how to go about properly setting up the models according to CakePHP convention -- or whether it is even a good idea to attempt this -- so I would appreciate any pointers anyone can give.
I am also happy to hear people's opinions even if the answer is not CakePHP-specific because this is more of a database question than anything else.

You can specify any association you want.
for example in your user Model:
/**
* #see Model::$hasAndBelongsToMany
*/
public $hasAndBelongsToMany = array(
'Area' => array(
'className' => 'Area',
'joinTable' => 'user_areas',
'foreignKey' => 'user_id',
'associationForeignKey' => 'area_id',
),
);
/**
* #see Model::$hasOne
*/
public $belongsTo = array(
'Farea' => array(
'className' => 'Area',
'foreignKey' => 'farea_id',
),
);

Related

One to many CakePHP3 (via matching table)

I was wondering, if it is possible to create a OneToMany Relationship in CakePHP3 via a matching Table in the DB.
This is what my DB looks like:
Showcase of DB Schema
This is my Table for ItemA:
$this->belongsTo('ItemB', [
'foreignKey' => 'item_a_id',
'targetForeignKey' => 'item_b_id',
'joinTable' => 'item_a_item_b'
]);
This is my Table for ItemB:
$this->belongsToMany('ItemA', [
'foreignKey' => 'item_b_id',
'targetForeignKey' => 'item_a_id',
'joinTable' => 'item_a_item_b'
]);
However, when I create a Control for ItemA in the template, it still gives me a Multiple Select.
echo $this->Form->control('item_b._ids', ['options' => $item_b, 'empty' => true]);
When I change this Form to Single Select, the selected Object will not be passed. I'm stuck to a Multiple Select :(
Is this the correct implementation of the DB Schema in Cake? Do I have to use the 'through' option? I'm confused...
Edit#1: It works if I configure ItemA with belongsToMany rather than belongsTo. But that would be a ManyToMany Relationship.
Traditionally, this isn't how you'd structure a one-to-many relationship. To enforce this at the DB level you would simply add tbl_item_a.id to the tbl_item_b table like:
tbl_item_b.item_a_id
However, by the sounds of it you know that already. And personally I don't see anything wrong with the setup as you have it, so long as it's documented (for others in the future).
By the sounds of it. The problem you're having isn't with the DB though, it's with the client-side rendering. For which you will want to use the select FormHelper function:
echo $this->Form->select(/*field name*/, /*[options]*/)

CakePHP 3.x Saving new record but also new associated record

So I'm developing a system where a user can create a new account and upload a profile photo. I'm using two models: User for the account, Photo for the photos.
The users table has a foreign key on the field photoId that references to photos.id. The photos table has a userId field that has a foreign key referencing users.id. So there is a recursive relationship between User and Photo. Reason for this: when a Photo is created, we want to be able to see which User uploaded the Photo. A User has one Photo as his profile image.
So it's Photo hasOne User and User hasOne Photo. They are also configured this way in their Table classes.
Now, when a new User is saved, we want to also save a new Photo. Photo needs the id of the newly created User in order to save, but the User needs the id of the newly created Photo.
My question: what is the best method to save this? Should we allow User.photoId to be null, so that we can first save the User, then save the Photo, and then update the User with the correct Photo.id, or can CakePHP3 do some magic where it does all of this linking back and forth for you?
Data that comes from the form:
[
'username' => 'John Doe',
'mail' => 'john#example.org',
'password' => 'whatever',
'photo' => [
'name' => 'myImage.jpg',
'type' => 'image/jpeg',
'tmp_name' => '/private/var/tmp/phpN3dVmL',
'error' => (int) 0,
'size' => (int) 40171
]
]
Make Things Simple !
Why you need hasOne relations for both table ?
It looks like you are making simple thing so complected.Let's talk about that:
You have two tables users and photos that's fine.
At the moment each user has one photo that's fine as well.
Just imagine one day user might have multiple photo, then ?
Then still no worries, everything would be good because you have photos table already.
So what kind of relations do you actually need here ?
Just like mentioned above, user has one photo, That's why relation should be:
user hasOne photo and obviously photo belongsTo user.
And you need nothing more than that.
Just for example
Fields on Users table
id
name
email
address
has_photo // eg:if has_photo = 1 user has uploaded photo,such field is not compulsary
password...etc
Fields on Photos table
id
user_id // foreign key of users table
name
size
Relations
// UsersTable.php
$this->hasOne('Photos', [
'foreignKey' => 'user_id'
]);
// PhotosTable.php
$this->belongsTo('Users', [
'foreignKey' => 'user_id',
'joinType' => 'INNER'
]);
Don't be confuse on that photos need user_id..users table never need photo_id.Because users table already associated with photos table. And if A hasOne B then B obviously belongs to A.That's the simple logic.
Don't hesitate to see the documentation ( Associations
) to get more information on relations..This is really important things for database management.
or can CakePHP3 do some magic where it does all of this linking back and forth for you?
Yes! As long as your associations are setup correctly Cake will take care of the rest. So the best method is to pass your data array into newEntity or patchEntity and make sure that all passed fields are accessible in you entity.
Saving hasOne relationships
Entities and mass assignment

Cakephp pagination with more than one order condition

Currently I have a table called as 'Users'. With columns like
Id, name, image, is_active, etc, etc, created, modified
I am setting up a pagination, where it will display all Users one by one, on click of next button(in the view)
here not all Users will have images. So my pagination order will be: to show users who have images first. Followed by Users who don't have images.
So far I have this
$this->paginate = array(
'limit' => 1,
'conditions' => array(
'User.is_active' => 0
),
'order' => array(
'User.image' => 'DESC'
),
'group' => array(
'User.id'
)
);
What I want is now, the view to FIRST display a random User, who has image, every time the page refreshes OR on the first load of the page. Followed by other Users who have images ,and then followed by Users who don't have images.
this query works fine in phpmyadmin sql panel. But I am not sure how do I write a cakephp paginate query for it
select * User order by image<>' ' desc,rand()
If you think I am missing any more data, please ask. I'll write it in comments
you can look at this answer SQL how to make null values come last when sorting ascending and try to change it with CakePHP conditions.
In your model you can set. I believe this works for the pagination order as well.
public $order = array(
'ISNULL(Users.image) ASC',
'RAND() * User.id'
);
But this makes all the users randomized. I don't know how you may do it to show only in the first record a random user with the order field. I would suggest using a custom function in which you may choose a random row and put it in the top of the array.

ATK4 How OneToMany retion can be used with multiselect?

I have 2 MySQL DB tables called roles (representing user access role) and modules (representing allowed modules per role). Each role can have many modules and each module can have many roles.
I want to add a crud representing roles table with a multiselect field allowing to select all related modules. What is the best way to do that. Thanks in advance.
There can be multiple solutions for this.
First one - use User CRUD with expander with Roles (should work):
$crud = $this->add('CRUD');
$crud->setModel('User');
if (! $crud->isEditing()) {
// add subCRUD
$sub_crud = $crud->addRef('UserRole', array(
'extra_fields' => array('role'),
'view_options' => array('entity_name' => 'Role'),
'label' => 'Roles'
));
}
Second one - use Grid with Roles + grid->addSelectable($fields) (not tested, but just to give you idea):
$grid = $this->add('Grid');
$grid->setModel('UserRole');
$grid->addSelectable('selected');
Third one - use two lists with roles (available roles and associated roles) and some buttons to "move" role from one list to another.
Something like this: (can't find link to appropriate Codepad page now) :(
There definitely can be even more ways to do this.

Kohana ORM store count in many-to-many relationship

I'm building a application using Kohana 3.2 and Kohana ORM.
The application has systems. Systems contain components. A system may contain multiple components, but also multiple components of the same type. E.g. System_A may have 10 Component_Y and 3 Component_Z
So instead of just having two belongs_to fields in my pivot table I also want to store the count.
If I just use a has-many-through I won't be able to access the count. Without ORM I'd just join the count onto the component in SQL, because the count is unique for the System + Component combination and so I can access the count for the component when I visit the object in the context of a certain system.
How best to go about this in Kohana ORM?
I solved it partially this way:
protected $_has_many = array(
'omvormer' => array(
'model' => 'omvormer',
'through' => 'systeemomvormer'
),
'systeemomvormer' => array(
'model' => 'systeemomvormer',
)
);
I've added the pivot tabel systeemomvormer separately to systeem.
I can now do this:
$so = ORM::factory("systeemomvormer");
$so->where('systeem_id', '=', $systeem_id);
$so->where('omvormer_id', '=', $omvormer_id);
$result = $so->find();
$result->aantal = $omvormer_count;
But it really still only is a partial solution, because I'm not able to update() the result. Kohana says that the result is not loaded. However that's outside the scope of this question and I'll open a new question for that.
This was also helpfull:
http://forum.kohanaframework.org/discussion/7247/kohana-3-orm-save-for-update-a-many-to-many/p1
To store more data in a junction table than just the two keys, you need to create a model for it.
So,
system _has_many system_component
component _has_many system_component
system_component _belongs_to component
system_component _belongs_to system
However, you may not need to store the count if you do it this way. Instead, you can do the following:
$system->components->count_all();
Then, to access them:
foreach($system->components->find_all() as $component)
echo $component->component->name;