Laravel get only models with current version - php

I have implemented custom model versioning in Laravel Framework. There is couple of columns handling it in the database table: sibling_id (links model's different versions together), version, accepted and validFrom.
For example:
| id | sibling_id | version | accepted | validFrom | ... |
|----|------------|---------|----------|------------|-----|
| 1 | 1 | 1 | 1 | 2017-12-01 | |
| 2 | 1 | 2 | 1 | 2018-06-01 | |
| 3 | 2 | 1 | 1 | 2017-12-10 | |
| 4 | 2 | 2 | 0 | 2017-12-28 | |
| 5 | 3 | 1 | 0 | 2017-12-01 | |
What I mean with current model:
model having the biggest version number within accepted and valid modals
OR version 1 if there isn't any other versions
I would like to have some way to get normally only current model grouped by sibling_id (so within this example the collection should include models 1, 3 and 5). This should work like same way than Laravel's withTrashed() function so that I can include all if I want to (for example version history).
Maybe this can be done somehow with the scopes but I felt it complicated because of the "sibling grouping" and another complex filters so I ended up to ask here.
Thanks in advance.

I think a SQL View would be easier to work with, rather than build the query with Laravel.
I'd build a view implementing the query something along:
select t.* from table as t
join (select sibling_id, MAX(version) as version from table group by sibling_id) as grouped
on grouped.sibling_id = t.sibling_id and t.version = grouped.version;
Then map another eloquent model for the view in Laravel. This way, you can just select from the table if you want to get all, or from the view if you want "unique" records.

Related

MYSQL UPDATE from SELECT INNER JOIN statement

Hello :) I am fairly new to using INNER JOIN and still trying to comprehend it's logic which I think I am sort of beginning to understand. After being across a few different articles on the topic I have generated a query for finding duplicates in my table of phone numbers.
My table structure is as such:
+---------+-------+
| PhoneID | Phone |
+---------+-------+
Very simple. I created this query:
SELECT A.PhoneID, B.PhoneID FROM T_Phone A
INNER JOIN T_Phone B
ON A.Phone = B.Phone AND A.PhoneID < B.PhoneID
Which returns the ID of a phone that matches another one. I don't know how to word that properly so here is an example output:
+---------+---------+
| PhoneID | PhoneID |
+---------+---------+
| 17919 | 17969 |
| 17919 | 22206 |
| 17919 | 23837 |
| 17920 | 17970 |
| 17920 | 22203 |
| 17920 | 23834 |
| 17921 | 17971 |
| 17921 | 22225 |
| 17921 | 22465 |
| 17921 | 24011 |
| 17921 | 24047 |
| 17922 | 17972 |
| 17922 | 22198 |
| 17922 | 23879 |
| 17923 | 17973 |
| 17923 | 22199 |
| 17923 | 23880 |
+---------+---------+
You can note that on the left there is repeating IDs, the phone number that matches will be on the right (These are just the IDs of said numbers). what I am trying to accomplish, is to actually change a join table relative to the ID on the right. The join table structure is as such:
+----------+-----------+
| T_JoinID | T_PhoneID |
+----------+-----------+
Where T_JoinID is a larger object with a collection of those T_PhoneIDs, hence the join table. What I want to do is take a row from the original match query, and find the right side PhoneID in the join table, then update that item in the Join to be equal to the left side PhoneID. Repeating this for each row.
It's sort of a way to save space and get rid of matching numbers, I can just point the matching ones to the original and use that as a reference when I need to retrieve it.
After that I need to actually delete the original numbers that I reset the reference for but... This seems like a job for 2 or 3 different queries.
EDIT:
Sorry I know I didn't include enough detail. Here is some additional info:
My exact table structure is not the same as here but I am only using the columns that I listed so I didn't consider the fact that any of the others would matter. Most of the tables have a unique ID that is auto incremented. The phone table has carrier, type, ect columns. The additional columns I felt were irrelevant to include, but if there is a solution that includes the auto incremented ID of each table, let me know :) Anyway, I sort of found a solution, using multiple queries though I am still interested to learn and apply knowledge based on this question. So I have a that join table that I mentioned. It might look something like this for the expected results. There is a before and after table in one sorry for poor formatting.
+--------------------+---------+----------+---------+
| Join Table Results | | | |
+--------------------+---------+----------+---------+
| Before | | After | |
| Join | Table | Join | Table |
| PersonID | PhoneID | PersonID | PhoneID |
| 1 | 1 | 1 | 1 |
| 1 | 2 | 1 | 2 |
| 1 | 3 | 1 | 3 |
| 2 | 4 | 2 | 1 |
| 2 | 5 | 2 | 5 |
| 2 | 6 | 2 | 6 |
| 3 | 7 | 3 | 5 |
| 3 | 8 | 3 | 5 |
| 3 | 9 | 3 | 5 |
| 3 | 10 | 3 | 8 |
| 3 | 11 | 3 | 9 |
+--------------------+---------+----------+---------+
So you can see that in the before columns, 7, 8, and 9 would all be duplicate phone numbers in the PhoneID - PhoneID relationship table I posted originally. After the query I wanted to retrieve the duplicates using the PhoneID - PhoneID comparison and take the ones that match, to change the join table in a way that I have shown directly above. So 7, 8, 9 all turn to 5. Because 5 is the original number, and 7, 8, 9 coincidentally were duplicates of 5. So I am basically pointing all of them to 5, and then deleting what would have been 7, 8, 9 in my Phone table since they all have a new relationship to 5. Is this making sense? xD It sounds outrageous typing it out.
End Edit
How can I improve my query to accomplish this task? Is it possible using an UPDATE statement? I was also considering just looping through this output and updating each row individually but I had a hope to just use a single query to save time and code. Typing it out makes me feel a tad obnoxious but I had hope there was a solution out there!
Thank you to anyone in advance for taking your time to help me out :) I really appreciate it. If it sounds outlandish, let me know I will just use multiple queries.

Database model for a multilanguage translation module

I need to design a db model for a backend module where user can translate page content into multiple languages. The things that will be translated are basic words, phrases, link names, titles, field names, field values. They should also be grouped so i can find them by group name. For example if there is a select field on page with different colors as options then i should be able to select all of them by group name.
So here is what i have at the moment:
lang
+----+---------+
| id | name |
+----+---------+
| 1 | english |
| 2 | german |
+----+---------+
lang_entity
+----+------------+-------------+-------+-------+
| id | module | group | name | order |
+----+------------+-------------+-------+-------+
| 1 | general | | hello | 0 |
| 2 | accounting | colorSelect | one | 1 |
| 3 | accounting | colorSelect | two | 2 |
| 4 | accounting | colorSelect | three | 3 |
+----+------------+-------------+-------+-------+
lang_entity_translation
+----+---------+----------------+-------------+
| id | lang_id | lang_entity_id | translation |
+----+---------+----------------+-------------+
| 1 | 1 | 1 | Hello |
| 2 | 2 | 1 | Guten tag |
| 3 | 1 | 2 | One |
| 4 | 2 | 2 | Ein |
| 5 | 1 | 3 | Two |
| 6 | 2 | 3 | Zwei |
| 7 | 1 | 4 | Three |
| 8 | 2 | 4 | Drei |
+----+---------+----------------+-------------+
So lang table holds different languages.
Table lang_entity has entities that can be translated for different languages.
Module row is just to group them by page modules in the backend translating module. Also this gives me possiblity to have entities with same name for different modules.
Group as mentioned is needed for selects and maybe some other places where multiple values are going to be used. This also gives me an option to allow user to add and order entities in one group.
And table lang_entity_translation holds the translations for each entity in each language.
So my question is are visible flaws in this kind of a design? Would you reccomend something different?
Also a bonus question: I really dont like the lang_entity table name, do you have a better idea of a table name that would hold all the words/phrases that are translated? :)
Edit: similar, but not a duplicate. The linked question is about translating dynamic products and having a seperate table for each translated type. Im talking about translating whole page content, including groups in a single table.
I don't understand the order column of lang_entity, but then I probably don't need to.
The setup looks sane, but make sure you add foreign key constraints from lang_entity_translation to language and lang_entity.
As for naming, I would call the table phrase or translatable.
We had similar situation. This was 7 years before.
We had different column for different language. Like for name we had
Name_Eng,Name_Ger,Name_Spa .We had 7-10 language.
We had common id for name for all language.
Based on the Language selection from UI we passed the language code to Back end In the Stored proc it was appended to the column Name
Example, we will be passing "Eng" if English is selected and we form the column name as Name_Eng and fetch the data. we were using dynamic query.

Laravel eloquent find max(date) with additional search criteria

I'm trying to figure out the best way to retrieve results from the database such that the created_at is the most recent, and also checking that another value (in this case Temps->value) matches a specific criteria..
For example (some information abbreviated)
LOCATIONS
+----+---------+
| ID | CITY |
+----+---------+
| 1 | DALLAS |
| 2 | CHICAGO |
| 3 | ATLANTA |
+----+---------+
TEMPS
+----+-------+----------+------------+
| ID | VALUE | CITY_ID | CREATED_AT |
+----+-------+----------+------------+
| 1 | 70 | 1 | 2010 |
| 2 | 95 | 1 | 2015 |
| 3 | 90 | 2 | 2010 |
| 4 | 80 | 2 | 2015 |
| 5 | 99 | 3 | 2015 |
+----+-------+----------+------------+
my location model.
class Location extends model
{
...
public function latestValue()
{
return $this->hasOne('App\Temp')->latest();
}
In this case I would only like the Locations in which the latest temperature reading is > 90..
In my controller if have
$highTemps = Location::with('latestValue')->get();
without iterating through every city explicitly, is there a way to adjust my eloquent relationship, or even use a collection method to filter the results?
I've looked at filter() but I'm not sure how to use that on a relationship. Especially if you're trying to filter 2-3 relationships deep. (imagine I'm starting off with Country->states->locations->temps->latestValue etc)
It would be great to have the initial query filter the results. But I can't figure out the combination of groupBy() and max() and having() etc to make the eloquent statement work.
I think the Relationship you are establishing, it's wrong..
The Problem is very simple if the relationship hasMany() will be used..
First all the latest entries will be fetched , followed by filtering the max out of them.
class Location extends model
{
...
public function latestValue()
{
return $this->hasMany('App\Temp')->latest();
}
rest is not that much typical i assume.

Doctrine multiple 1 to 1 connections

I have task that would be quite simple using regular SQL query but the project is built using doctrine and I am looking for an optimal solution. Maybe someone could advise what would be a good way to approach this.
I have a quite complicated db structure but the simplified version of objects in question look like this:
| Category | | Product | | ProductOption |
------------ --------------- --------------------
| id | | id | | id |
| name | | category_id | | product_id |
------------ | name | | some_data |
--------------- --------------------
Product Option and Product have 1 to 1 connection. But options are created per category (I get 1 entity per category, but need to replicate that entity for every product and store that as 1 to 1 since at some point those options will need to be edited individually. Now there are many ways to do that (the dirty way) , but I would like some advice on how to do that in the most optimal way.

Relate two MySQL tables?

I'm kind of stuck in a pickle trying to make two separate database tables related to each other by two columns.
On my website I have a set of classes along with a set of objectives which belong to each class. Classes are stored in their own database table, and so do the objectives in their own table as well.
I want the user to be able to manually set the start and end dates for any objective for an active class, and when this happens it needs to update in the database as well. My trouble comes from trying to visualize how this is all supposed to happen, and how the tables in the database should handle this. All help is greatly appreciated on this. Thanks
EDIT: This is my current table design. (I don't know how to make a proper table on here yet, so I'll just create a rough draft of the design.)
Classes
class_id | instr_id | class_name | start_date | end_date |
1 | 1 | Class1 | 2013-05-10 | 2013-05-30 |
2 | 2 | Class2 | 2013-05-10 | 2013-05-30 |
3 | 3 | Class3 | 2013-05-10 | 2013-05-30 |
.. and so on for each class.
Objectives
class_id | objective_id | start_date | end_date |
1 | 1 | 2013-05-10 | 2013-05-30 |
1 | 2 | 2013-05-10 | 2013-05-30 |
1 | 3 | 2013-05-10 | 2013-05-30 |
2 | 1 | 2013-05-10 | 2013-05-30 |
2 | 2 | 2013-05-10 | 2013-05-30 |
2 | 3 | 2013-05-10 | 2013-05-30 |
... and so on so every class has every objective_id, assuming each
class has only 3 objectives.
I really hope this helps clarify some things.
Where there is a many-to-many relationship between two relational tables (as described here - one objective can be set for many classes, and each class can have many objectives), this should normally represented by a link table, which will have a many-to-one relationship with each of the parent tables.
Here, the link table could be called something like objective_assigned (as shortened form of "Objective assigned to Class") - it might have a structure like:
class_id
objective_id
start_date
end_date
- with a compound primary key on class_id and objective_id.
I would also expect an Objective table to exist, with a primary key of objective_id and a column to hold the objective title/name.

Categories