I want to know how to make relations between tables:
I have a shops table and a users table.
I want to associate to the users table: shops (id) AND area (that's a group of shops).
I don't know how to do that in a beautiful and right way.
For example, in a very complex way we can have:
Area A contains [Area B (3 shops) and Area C (1 shop)] and 1 shop : total of 5 shops.
John is associate to the Area A, Area X and 3 other shops (no area).
How to represent this in database?
It's like a recursive thing :(
Thanks by advance!
You'd probably want to have the following tables:
users
- id
- username
shops
- id
- name
areas
- id
- name
- parent_id
user_shop
- user_id
- shop_id
area_shop
- shop_id
- area_id
Then for your example, a row might look like
users
id: 1
username: jappleseed
shops
id: 1
name: some shop name
id: 2
name: some other shop name
areas
id: 1
name: Area A
parent_id: null
id: 2
name: Area B
parent_id: 1
id: 3
name: Area C
parent_id: 1
area_shop
area_id: 2
shop_id: 1
area_id: 2
shop_id: 2
Then you could define your relationship for nested areas like:
class Area extends Model {
/**
* Parent Area
*/
public function parent_area()
{
return $this->belongsTo('Area', 'parent_id');
}
/**
* Child Areas
*/
public function child_areas()
{
return $this->hasMany('Area', 'parent_id', 'id');
}
}
The other relationships should be fairly straight forward.
This is untested and might need a little tweaking, but the overarching idea should get you there. Otherwise, using a prebuilt nested set library would also work.
Related
I have 2 tables i.e. users and user_managers, with the following structure and data:
users
id
name
employee_number
1
Employee One
ACB1234
2
Employee Two
XYZ1234
3
Employee Three
EFG1234
4
Employee Four
HIJ1234
user_managers
id
user_id
manager_of_user_id
1
1
2
2
2
3
3
4
1
4
5
4
I want a recursive function to get the complete chain of the managers. For example, if query for user_id = 4, I should get the following result:
result
user_id
name
employee_id
comments
1
Employee One
ABC1234
user managed by 4
2
Employee Two
XYZ1234
user managed by 1
3
Employee Three
EFG1234
managd by user 2
5
Employee Five
JKL1234
manager of user 4
The table above is just for the clarification, I am looking for a recursive function to get the above result.
I have tried the below solution but it is working for only 1 level.
public static function getCompleteChain(User $user)
{
$managerUsers = $user->managers;
foreach ($managerUsers as $manager) {
$manager->user = User::where('employee_id', $manager->manager_of_user_id)->first();
self::getCompleteChain($manager->user);
}
return $managerUsers;
}
Thanks in advance.
CONTEXT
I am managing products. This is a shoe store. I would like to offer a view of the other variants.
The database is shaped like this:
For example you can have a leather shoe (id 1), and there is 3 variants of this shoe: a black (id 1), a brown (id 2), and a grey (id 3).
What I try to do is to construct a Laravel relationship to be able, from one variant, to get its siblings. Here is what it looks like in the database according to the example I mentioned.
SHOE
id
====
1
SHOE_VARIANT
id shoeId colorId
===================
1 1 1
2 1 2
3 1 3
...
8 2 5
9 3 2
10 3 4
In this case, if the user is viewing the black variant (id 1), I whish I could show him the 2 others variants (brown, id 2, and grey, id 3).
QUESTION
How can I construct a Laravel relationship in order to retrieve siblings from a parent id, and make sure the current record itself is not included?
EXPERIMENTS
I already tried to construct a relationship like below, but the current record itself is included and I can't figure out how to exclude the record itself because I did not find how to get the current id of the record.
// app/ShoeVariant.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class ShoeVariant extends Model {
public function siblings() {
return $this->hasMany("App\ShoeVariant", "shoeId", "shoeId");
}
}
This means:
For the current shoe variant, get the shoe variants that matches knowing that you should match the foreign column named "shoeId" and the local column named "shoeId"
So if 2 shoe variants share the same column "shoeId", this works. Stuck in excluding the current record from these results.
This should do what you want:
public function siblings() {
return $this->hasMany('App\ShoeVariant', 'shoeId', 'shoeId')
->where('id', '!=', $this->id);
}
Just filter out the current variant by id and get all the others.
Alternatively, you can just make a new property:
public function getVariantsAttribute() {
return $this->siblings->reject(function($elem) {
return $elem->id == $this->id;
});
}
And then use it in code like:
$variants = $model->variants; // all except this one
I have two tables: products and products_actions.
When the user clicks away a product, I want this action to be stored in products_actions. The field has_removed will be 1 then.
I would like to present to the user only those products that he has not clicked away.
Currently I have the following entries in my tables:
Table "products":
id: 1
name: Product 1
id: 2
name: Product 2
id: 3
name: Product 3
Table "products_actions":
id: 1
id_product: 2
has_removed: 1
If the user has not removed a product from his page so far, there will be no corresponding entry in the products_actions table.
So my query is:
$qb->select('p')
->leftJoin(
'ProductsActions',
'pa',
'WITH',
'pa.idProduct = p.id'
)
->where('pa.hasRemoved != 1');
How do I achieve that my query aboves delivers "Product 1" and "Product 3" as entries?
I am not entirely clear what you need. I guess you are talking probably like this :
select * from products where id not in (select id_product from products_actions where hasRemoved = 1)
I'm using Laravel4 on my project and I have those tables on Mysql Database ..
Users :
- id - username
1 - user1
2 - user2
-
Blogs :
- id - blog_name
1 - blog1
2 - blog2
-
Roles :
- id - role_name
1- owner
2- editor
-
Assigned_roles:
- id - role_id - user_id - blog_id
1 - 1 - 1 - 1 // user1 owns blog1
2 - 2 - 1 - 2 // user1 editor in blog2
In laravel, I can successfully deal with three tables using hasMany and BelognsToMany relationship .. but 4 tables! it was too complecated for me,
I have spent 2 days on this but I couldn't figur out how to achieve this in a simple way with one query or so.
What I'm trying to do is, When I login in to blog1 , I need to list all blogs that I have access on them , for example :
blog (owner)
blog2 (editor)
something like..
$user = User::find(1);
print_r($user->access_blogs); // list blogs that I have assigned roles to them
and maybe later ..
$myrole = Blog::find(1)->where('user_id', 2);
echo $myrole->myrole; // editor
--
// 1
use LaravelBook\Ardent\Ardent;
class User extends Ardent {
public function blogs()
{
return $this->hasMany('Blog');
}
}
// 2
use LaravelBook\Ardent\Ardent;
class Assignedroles extends Ardent {
protected $table = 'assigned_roles';
}
.. etc , you got the idea .. :)
I have a parent category that holds all Cars names, denoted by parent_name in table "parent". For each of these parents, there could be any number of car models & they all go in table called "model". Each of these models can have any number of images & refereced via the model_id as the Foreign Key. My task is to show all the Parent Name only once (as in a group) and at the same time, list all the models under that Parent with just 1 corresponding image. The parent_name should not be shown more than once.
MY EXPERIMENTS:
I basically tried to write 2 queries. One was to left join "parent" table on "models" & use GROUP BY parent_id and then in the while loop, write another query to fetch only 1 image using by joining the models & images tables by using model_id field. But doing this lists only 1 Model, even though there are multiple models. So I tried to use GROUP BY parent_id, model_id. Using this does show all the models but at the same time, also repeats showing the parent_name & I need the parent_name to show only once throughout the page. You can say that I am trying to GROUP the model_name under the parent & show all the models under a single parent and I am showing only 1 image of the model. If somehow I can avoid showing the parent_name multiple times, the issue would be solved.
Following are my table schemas:
//Table parent
parent_id parent_name
1 Par1
2 Par2
//Table model
model_id parent_id model_name
1 1 Model1
2 2 Model2
3 1 Model3
4 1 Model4
5 2 Model5
//Table model_images
image_id model_id
1 1
2 1
3 1
4 2
5 3
6 3
DESIRED OUTPUT:
Par1 ---> This is the parent. Needs to be shown only once.
Model1 --> This is a model. List all models that belong to this parent.
image_id 1 -> Show only 1 image of the model (model may have multiple images but I need just one)
Model3 --> This is a model.
image_id 5 -> Show only 1 image of the model
Model4 --> This is a model.
No Image -> Note that no image exists for this model. So we show "No Image" text.
------------------------------------------------------------
Par2 ---> This is the parent. Needs to be shown only once.
Model2 --> This is a model.
image_id 4 -> Show only 1 image of the model
Model5 --> This is a model.
No Image -> Note that no image exists for this model. So we show "No Image" text.
I need the PHP & mySQL code to achieve the above. All help in resolving the issue is appreciated.
Thank you very much.
EDIT 1:
Sorry, I forgot to add this. I am non-object oriented programmer. So I would really be thankful if you can avoid object oriented code in your solution and show me the same in a non-oops way. Thanks.
You might do it in one query and than combine it to an associative array:
$query = ' SELECT *
FROM parent AS p
LEFT JOIN model AS m
ON p.id = m.parent_id
LEFT JOIN model_images AS m_i
ON m.model_id = m_i.model_id';
$array = array();
if($mysli->query($quer)){
while($row = $result->fetch_assoc()){
$array[$row['parent_name']][$row['model_id']] = $row;
}
}
You will than have an associative array with the parent name as the key of the array. You can then use a for loop to print the key only once (with $i = 0) but the rest value by value.
Is that clear enough?
EDIT: Your array than might look like this:
Array(
'Par 1' =>
Array(
[0] => Array(
'parent_id' => 1,
'parent_name' => 'Par 1',
'model_id' => 1,
'model_name' => 'Model 1',
'image_id',
),
[1] => Array(...)
),
'Par 2' => Array(...)
)
So to print out you need two loops. One for the parents (and there names) and one for their childs (models in this case).
foreach($array as $par_name => $models){
echo 'Parent name: '.$par_name.'<br />';
echo 'Model ID: '.$models[0]['model_id'].', Model Name: '.$models[0]['name']; // replace with your desired output
}
Now an idea of how it works? An sure as Artefacto said, you can use procedural functions if you don't like OOP functions.