Working on a site where a user can add videos. Each video can be in many sections. It can also have many questions. Video has a one-to-many relationships with both the question and section classes.
I'm getting the section and video classes like this:
$s = new Section();
$s->where('section', $this->post->section)->get();
then saving like this:
$v->save($u, $s, $q);
where $v is a video object, $u is a user object and $q is a question object.
I want to allow the user to POST multiple questions and sections. How do I save those relationships. Should $s and $q be arrays of objects?
I am not 100% sure that I understand what you mean but yes yu can save multiple relations at the same time.
Like this:
$s = new Section();
$s->where_in('section', $array_with_sections_ids)->get();
$v->save(array($u, $s->all, $q));
You use different tables in your database. Like Video, Question and VideoQuestion where you store the video ID with the different Question id's
Then VideoExample would look like:
| video_id | question_id |
--------------------------
| 1 | 1 |
| 1 | 5 |
...
for inserting this data, first insert the video and get its ID with
$videoId = $this->db->insert_id()
Do the same for your question and you've got your ID's ;)
The same for the other tables and you're done. Good Luck!
Related
I'm working on an older project that I've been tasked to speed up certain parts of while we work on a complete re-write since the code is just badly maintained, poorly written and outdated for what it's suppose to do.
I stumbled into an issue to the core of the project and because of this I can't change it without breaking almost everything else. So I need to load a "relation" the eloquent way (using Planning:with('availability') but there isn't a real foreign ID, it rather laps with multiple fields.
Would there be a way to load it all in one query with the overlapping fields rather than have it load separately creating an n+1 problem?
+--------------+-----------------+
| Planning | Availability |
+--------------+-----------------+
| planning_id | availability_id |
| date | date |
| startHour | startHour |
| stopHour | stopHour |
| candidate_id | candidate_id |
| section_id | section_id |
+--------------+-----------------+
From the above example you can see the overlapping fields are date, startHour, stopHour, candidate_id and section_id.
I tried get...attribute but that still loads with n+1, I tried including it with ->with(['availabilities']) but that doesn't work since I ask for the
model and not the relation:
Edit for more clarity:
Planning Model:
public function availabilities()
{
return Availability::where('section_id', $this->section_id)
->where('candidate_id', $this->candidate_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour)
->get();
}
public function availabilities2()
{
return $this->hasMany('App\Models\Availability', 'candidate_id', 'candidate_id')
}
Controller:
$plannings = Planning::with(['availabilities'])->get();
$plannings = Planning::with(['availabilities2' => function ($query) {
// $this is suppose to be Planning model but doesn't work
$query->where('section_id', $this->section_id)
->where('planningDate', $this->planningDate)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
// ---- OR ---- //
// Don't have access to planning table here
$query->where('section_id', 'planning.section_id')
->where('planningDate', 'planning.planningDate')
->where('startHour', 'planning.startHour')
->where('stopHour', 'planning.stopHour');
}])->get();
First of all to be able to load my relation I took one of the keys that matched and took the one which had the least matches which in my case was section_id.
So on my Planning model I have a function:
public function availabilities()
{
return $this->hasMany('App\Models\Availability', 'section_id', 'section_id');
}
This way I can load the data when needed with: Planning:with('availability').
However since I had a few other keys that needed to match I found a way to limit this relation by adding a subquery to it:
$planning = Planning::with([
'availabilities' => function ($query) {
$query->where('candidate_id', $this->candidate_id)
->where('startHour', $this->startHour)
->where('stopHour', $this->stopHour);
},
// Any other relations could be added here
])
->get();
It's not the best way but it is the only way I found it not getting too much extra data, while also respecting my relationship
When you want to use multiple fields in where() method you most insert a array in the where() method:
This document can help you
change your code to this:
return Availability::where([
['section_id', $this->section_id],
['candidate_id', $this->candidate_id],
['planningDate', $this->planningDate],
['startHour', $this->startHour],
['stopHour', $this->stopHour]
])->firstOrFail();
I am working with laravel and eloquent, I'm sorry if this is a stupid question, I've already made some search on google but couldn't find something like this.
I have a Company model which has a "hasMany" relationship with a CompanyProperties model. The CompanyProperties has two columns: "name" and "value".
id | Name | Value
1 | primaryColor | #000
2 | secondaryColor | #333
When I get the companies with Company::all(); it loads perfectly the CompanyProperties of each company. Every CompanyProperty returns a collection, which I can access using $company->CompanyProperties[0...n].
What I'd like to do if it's possible is that the CompanyProperties are accessible using the "name" column value as property or as an array. Using the example of my table above:
$company->CompanyProperties['primaryColor']
or
$company->CompanyProperties['secondaryColor']
Is there a way to do this?
Oh yea, many thanks in advance. I appreciate any advice you could have on this (even if I have to change the "properties" approach, haha).
Laravel 5.1 and before: Use the lists method
Laravel 5.2: Use pluck
$properties = $company->companyProperties()->pluck('Value', 'Name');
This returns an array where the value is the the 1st argument ('Value') and the key is the 2nd argument ('Name'), e.g.
$value = $properties['primaryColor']; // '#000'
However, this can be pretty inefficient because you're running a query for each company that you fetch. If it's just one or a few companies that's ok but given that you're using Company:all() I would recommend eager loading:
$companies = Company::all();
$companies->load([
'companyProperties'
]);
That will fetch the properties for all companies in a single query. Now for every $company, $company->companyProperties is a Collection. So you can use the keyBy method:
foreach ($companies as $company) {
$properties = $company->companyProperties->keyBy('Name');
$value = $properties['primaryColor']->Value; // '#000'
}
Notice that the syntax is slightly different, $properties['primaryColor'] is still a companyProperties object, so you have to get the attribute ->Value
Yo all,
I have a users relationship pivot db table as follows:
id | user_id | relation_id | relationship
1 4 2 tutor
1 4 3 parent
The table relates user with one-and-other for various reasons.
I am trying to get the relationship column within the $user. I have managed to pull the related users
details no problem - $user->relations.
However, I just need to get the relationship - eg. Tutor or parent.
I am getting no dice with $relative->pivot->relationship
Any ideas? Thanks for taking the time to help.
#foreach($user->relations as $index=>$relative)
{{ $relative->first_name . ' ' . $relative->last_name}}
{{ $relative->pivot->relationship }}
#endforeach
To access ->pivot->whatever you need to add withPivot('whatever') to the relation definition:
public function relations()
{
return $this->belongsToMany('Relation')->withPivot('relationship');
}
Note: I wouldn't use relations and Relation names here, since it's misleading AND it may collide with Eloquent\Model stuff.
I'm making a table that essentially maps rows in a table to rows in another table where the structures are as follows:
|--- Words --| |- Synonyms -|
|------------| |------------|
| id | | id |
| en | | word_id |
| ko | | synonym_id |
| created_at | | created_at |
| updated_at | | updated_at |
|------------| |------------|
Now then, I know I can essentially have the words model have many Synonyms through a function like:
public function synonyms()
{
return $this->hasMany('Synonym');
}
No problem, but this method always gets it by the the word_id, and I would like to get it from word_id OR synonym_id that way I don't have to make multiple entries in the DB.
Is there anyway I can do this?
Check laravel docs Eloquent relationships. It would only get word_id because that's the only foreign key I believe.
Also why do you have synonym_id in your Synonyms table?
I believe you are looking for polymorphic relationship.
http://laravel.com/docs/eloquent#polymorphic-relations
I think your best bet is to create a many-to-many relationship with words on itself using the synonyms table as your pivot table.
Add this to your Word model.
public function synonyms()
{
return $this->belongsToMany('Word', 'synonyms', 'user_id', 'synonym_id');
}
Using it:
$word = Word::where('en', '=', 'someword')->first();
foreach($word->synonyms as $synonym) {
// This method would probably return the same word as a synonym of itself so we can skip that iteration.
if($synonym->en == $word->en) {
continue;
}
// Echo the synonym.
echo $synonym->en;
}
I'm a bit confused on you wanting to be able to find synonyms by the word_id or synonym_id but I think if you are using the many-to-many, it won't matter because if you know the synonym, it's still technically just a word, and you'd do the exact same thing.
Is it possible to create a parent name field into one-to-many relationship in Propel ORM.
This type of relationship uses in CRM systems.
Just imagine that we have a Task List. So, we created a Task #1 and related it to a Project.
Task #2 is related to Account (e.g. create a contract).
Task #3 is related to Bug Tracker (e.g. fix a bug).
So, we have the following relationships:
task_name | parent_name | parent_id
--------------------------------------------------
Start a project | Project | <project_id>
Create a contract | Account | <account_id>
Fix a bug | Bug Tracker | <bug_id>
Is it possible to implement in Propel. If no, could you recommend me another ORM with this feature.
The main purpose is to get a list of records with all relationship values.
For my example, it should look like (in JSON):
{
"Task_0":{"Id":1,"Name":"Start a project","ParentId":1,"ParentName":"Project","Project":{"Id":1,"Name":"Project-1","Tasks":{"Task_0":"*RECURSION*"}}},
"Task_1":{"Id":1,"Name":"Create a contract","ParentId":1,"ParentName":"Account","Account":{"Id":1,"Name":"Account-1","Tasks":{"Task_0":"*RECURSION*"}}},
"Task_2":{"Id":1,"Name":"Fix a bug","ParentId":1,"ParentName":"Bug","Bug":{"Id":1,"Name":"Bug-1","Tasks":{"Task_0":"*RECURSION*"}}}
}
Does anyone help me?
The output you have shown looks as if the toArray function has been used on the Propel objects and then the json_encode function. This should work if you define foreign keys mutually in Propel's schema.xml.
Since project tasks, account tasks and bug tracker tasks all have something in common, they all are tasks :), I would organize them as sub classes of a more general task entity.
You will end up with a collection of tables like this:
Table "task"
id | name
------------------------
1 | Start a project
2 | Create a contract
3 | Fix a bug
4 | Start another project
5 | Fix another bug
---------------------------------------
Table "bugtrack_task"
id | id_task
---------------
1 | 3
2 | 5
---------------------------------------
Table "project_task"
id | id_task
---------------
1 | 1
2 | 4
---------------------------------------
Table "account_task"
id | id_task
---------------
1 | 2
In the end, you would define a view in the schema.xml. This could look something like this:
<table name="view_task" phpName="ViewTask" skipSql="true" readOnly="true" description="All my tasks together for display">...</table>
Note that the skipSql attribute has been set to true. This will skip this view table when generating the SQL code. Propel will generate the classes for you but won't touch your database. You can now manually define the view yourself putting into it whatever you desire.
Of course you'd have to put some effort into creating this view but it pays off as you will be able to use the Propel classes like so for instance:
$tasks = ViewTask::create()->find();
$result = array();
foreach($tasks as $task) {
$result[] = $task->toArray();
}
return json_encode($result);
This isn't a complete answer but I hope you see the idea! Good luck :-)