Yii2: How to order a relation by virtual attribute? - yii2

I have a class Group, which hasMany Teams and I would like to order them by their score. A team's score is calculated by iterating through its games, so score is not a db-field, it's a virtual read-only attribute.
This is my attempt:
public function getTeams()
{
return $this->hasMany(Team::className(), ['group' => 'id'])->orderBy(['score' => SORT_ASC]);
}
This does not work, as score is not a db-field. How can I order a relation by a virtual attribute?

You can create a database view, e.g. team_score. The view should contain all the fields from the team table and a calculated field score (calculated with SQL commands). Then you can create a model TeamScore, which you can quite easily order by the field score.
Disadvantage: The values will be by every calling the view new calculated, what requires more compute power, than when the calculated values are directly stored in the table.
Advantage: It is simple to implement and firstly for displaying tables with many relations it saves a lot of coding.

Related

Interface between MySQL dynamic metadata and static properties

I have a MySQL database that has over 50+ tables and constantly increasing but as an example assume the following tables:
dynamic (entity, attribute, value) following a EAV model
tasks (id, name, duration, type, start_date, finish_date, user_id, ...)
users (id, first_name, last_name, username, join_date, ...)
I am working on a dashboard to allow user-created charts which reads from the dynamic table and user can filter through entity, property & values however the user would not be able to access 'static' columns belonging in different tables (e.g. output count of tasks with duration > 2 days).
Two approaches I have brainstormed to tackle this:
Approach 1 -
Create a view table using a cron job to extract all columns and values of every 'static' table in a EAV model where the entity = table name, attribute = column name and value = row value and join with 'dynamic' table, this way the table is in a standardised format where the user can easily pick the attributes to filter/report.
Advantages would be no backend coding required every time a new table is added to the database as the cron will pick up all tables.
Disadvantages are doubling up records and also crons have to run at intervals so the reporting data will not be up-to-date unless cron runs more frequently and consequently consuming more resource.
Approach 2 -
Hard code every table and column as a selection option so the user can select from predefined tables and columns.
Advantages are that there's no double-ups and the information is accessibly easily via SELECT queries.
Disadvantages would be every time a new table is added, it needs to be hard-coded as a predefined option and certainly a lot of if-statements in backend to support different tables and properties. It would need constant updates given the number of tables.
What is the best way to approach this? I believe there must be a better way to do this than the above.

Laravel pivot table need to have duplicate entries

I am using Laravel to build a small customer list system.
I need to link COMPANY with CONTACT_PERSON. In a normal situation, I can use many to many pivot tables to link and update them.
However, I need to keep historical records. That means the same person can act as a contact in the period earlier, resigned, and reappointed later with another period.
I try to duplicate the pivot table entries with phpMyAdmin, makes the same COMPANY linked the same CONTACT_PERSON twice, and two entries were found when retrieving the COMPANY records.
However, how can use Laravel duplicate the entries? How to use Laravel to CURD those. Or I just do it in the wrong way?
Thank you very much!
EDIT :
Example :
Company A employed Mr. A between 01-01-2001 till 02-02-2001,
Compnay A employed Mr. A again on 03-03-2001 till 04-04-2001.
There are company B,C,D ... in company table,
There are Mr. B, C , D in the employee table too.
Use Laravel relationship pivot table to link company A to Mr. A will have two records in the above case (I need to have a historical record).
Is it the right way to handle such cases with Laravel many to many relationships? Or I should consider other ways ?
A pivot table can contain additional columns. You could consider adding migrations that add a started_at and resigned_at datetime field to your pivot table.
Your data structure would look something like this:
Company
id
...
Contact_person_company
contact_person_id
company_id
started_at
resigned_at
Contact person
id
...
After that, you could create functions in your model to work with the pivot columns and check for their status. A null value for the resigned_at column indicates that the ContactPerson is still active.
<?php
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Company extends Model
{
// ... other functions
public function contactPersons(): BelongsToMany
{
$this->belongsToMany(Company::class)
->withPivot('started_at', 'resigned_at')
->wherePivotNull('resigned_at');
}
public function resignedContactPersons()
{
$this->belongsToMany(Company::class)
->withPivot('started_at', 'resigned_at')
->wherePivotNotNull('resigned_at');
}
}
You should define these functions as well on the ContactPerson model.
If the logic gets very complicated, consider creating a Pivot model (CompanyContactPerson).
Please note that the combination of contact_person_id, company_id started_at should be unique. Otherwise, considering adding a primary key like ID the company_contact_person table to identify these records.

Creating a temporary table from inside Controller in Laravel PHP

I'm making a Laravel website which is a musician directory. Every Musician has many Skills and Genres.
I want the user to be able to make advanced searches by specifying various skills and genres.
The results are then to be retrieved and sorted by relevance.
Example:
User specifies skills: "Guitar", "Theory", and genres "Jazz", "Rock", "Blues".
A Musician with the skills: "Guitar", "Bass", and genres "Jazz", "Funk" gets a relevance score of 2 because he has two matching tags.
My plan is to make a temporary table inside of the MusiciansController search() function which stores all the results for the user's search.
How would I go about doing this if even possible?
I suggest making this a little easier on yourself by designing this slightly differently. Instead of thinking about a 'temporary' table, create an actual Laravel model and create all the functionality (calculations of relevance, user, etc) within.
By having a model / DB connection, you can also use Laravel relationships and call the methods on that model in a scalable way in future -- IE if you want to add new relevance calcs, or different relationships, you don't have to modify an SQL view - just add a method.
If you want to simulate a temporary table, just have a cleaner function at the start of the next search to wipe the previous records in the DB for that model.
Lastly, ask yourself if you even need to store this in a table, or can you calculate it using some set of formulae within the controller's methods.

Separate Users Across 2 Tables?

I'm building a Ruby on Rails application, I'm separating two sets of users:
Buyers
Sellers
Currently someone built the database with both under a Users table with:
t.string "user_type", default: "buyer", null: false
There are some additional data I will need to hold for Sellers and there is also a few features/pages I want Sellers to have access to, but not Buyers.
For example I want to hold bank details so I can pay Sellers what we are paid by Buyers (we hold payments for a few days to ensure safe transaction). So the additional data may be:
Account Number
Sort Code
We do not need to store this data for Buyers since they use Stripe for payment.
Do we include the data on the current Users table? or do we create a new Sellers table that is linked to the Users table?
You can use one table and have the differences in the models. As users, they will share many common features, e.g. authentication during sign_in, change password, etc.
class User < ActiveRecord::Base
...
end
class Buyer < User
def buyer_specific_method_one
...
end
end
class Seller < User
def seller_specific_method_one
...
end
end
And add a string field named 'type' to the user table. See Single Table Inheritance.
There is a number of options you can use. Not necessarily one, some combinations are possible:
Factor out differences (bank details?) into separate models with one-one relationships with User
You can make them one-many later if you need to, one seller may provide info for multiple banks
You do not restrict your users from being both buyer and a seller simultaneously (if you want)
If these details are not needed on every single request, the performance penalty is not too big
Single Table Inheritance
Alter the string column user_type to be just type, then make two more models without a table (--no-migration), inheriting not from ActiveRecord::Base, but from User, so they inherit its table for persistence
Your users table will need to have all the columns from all subclasses
Any User subclasses (like Buyer) will be defined as a User with certain type ("Buyer")
Serialize attributes that you'll be processing on app level only, not in the database
You'll need to create a text-type column for each collection of serialized attributes that you want
You'll only be restricted by the format of serializer, not database columns and types, it allows you to store arbitrary data there
You can define a custom serializer that outputs custom objects (maybe even models?)
Be extra careful not to allow users to arbitrarily edit collections
Make sure you only need serialized data from already loaded objects, contrary is a design flaw

linq2sql, one to many through relations

I have
OrgUnits,
OrgUnitJobs,
Employees,
OrgUnitJobEmployee (this one may seem redundant in this context, its here fyi)
tables.
org units have jobs defined in OrgUnitJobs (1..n)
employee (can also have many jobs) has jobs defined in OrgUnitJobEmployee table.
and employee has a PrimaryJob (1..1) in OrgUnitJobs table, so how do I get a list of all the employees who's primary job is in that org unit.
I am using LINQ2SQL ORM, so I have an OrgUnit partial class, I would like to be able to get this employee list within that partial ORM class, without writing another query, or a linq select.
I just dont want to go to my OCRepository class and write a GetEmployeeListForOrgUnit(orgUnitId) there, it does not sound right.
Check DataContext.LoadOptions to tweak what's included in the first query. This means it'll execute a join, instead of N subqueries.
In your case, something like:
DataLoadOptions dlo = new DataLoadOptions();
dlo.LoadWith<Job>(j => j.PrimaryEmployees);
dbContext.LoadOptions = dlo;