Using Array of ids vs join table Laravel Eloquent - mysql

I am creating a Laravel Application with Eloquent connected to MySQL DBMS where I have three models:
Product
ProductGallery
File
I have also the following relations
One Product has one ProductGallery
One ProductGallery has many File
My question is:
Is it okay if I store images in ProductGallery as an array of file_ids
instead of creating a join table or having gallery_id in File model?
public function setImagesAttribute($images)
{
$this->attributes['images'] = serialize($images);
}
public function getImagesAttribute()
{
if (empty($this->attributes['images']) || is_null($this->attributes['images'])) return [];
return unserialize($this->attributes['images']);
}
I am asking this question to know if there is any side effects for this method
and in the future there might be other models related to File model (Category may have featured image file and so on).

In my opinion Better Option is creating a pivot table.. Because further when you have to join , you pull the array and you have to execute a query under a loop that is bad..

Related

Laravel Eloquent - auto-numbering on has many relationship

I'm very much a beginner when it comes to database relationships hence what I suspect is a basic question! I have two database tables as follows:
Projects
id
company_id
name
etc...
rfis
id
project_id (foreign key is id on the Projects table above)
Number (this is the column I need help with - more below)
question
The relationships at the Model level for these tables are as follows:
Project
public function rfi()
{
return $this->hasMany('App\Rfi');
}
RFI
public function project()
{
return $this->belongsTo('App\Project');
}
What I'm trying to achieve
In the RFI table I need a system generated number or essentially a count of RFI's. Where I'm finding the difficulty is that I need the RFI number/count to start again for each project. To clarify, please see the RFI table below which I have manually created with the the 'number' how I would like it displayed (notice it resets for each new project and the count starts from there).
Any assistance would be much appreciated!
Todd
So the number field depends on the number of project_id in the RFI table. It is exactly the number of rows with project_id plus one.
So when you want to insert a new row, you calculate number based on project_id and assign it.
RFI::create([
'project_id' => $project_id,
'number' => RFI::where('project_id', $project_id)->count() + 1,
...
]);
What I understood is that you want to set the value of the "number" field to "1" if it's a new project and "increment" if it's an existing project. And you want to automate this without checking for it every time you save a new row for "RFI" table.
What you need is a mutator. It's basically a method that you will write inside the desired Model class and there you will write your own logic for saving data. Laravel will run that function automatically every time you save something. Here you will learn more about mutators.
Use this method inside the "RFI" model class.
public function setNumberAttribute($value)
{
if(this is new project)
$this->attributes['number'] = 1;
else
$this->attributes['number']++;
}
Bonus topic: while talking about mutators, there's also another type of method called accessor. It does the same thing as mutators do, but just the opposite. Mutators get called while saving data, accessors get called while fetching data.

cakephp retrive data from one table excluding the associated tables

I am struggling with a basic problem. i am using cake php 2.5. i try to apply the find query in the company model and receiving all the data from companies and with its associations, but i only want to receive the data from company table and want to exclude the data from rest of relationships, can anyone help me with this. below are my queries.
$this->loadModel('Company');
$fields=array('id','name','logo','status');
$conditions=array('status'=>1);
$search_companies = $this->Company->find('first',
compact(array('conditions'=>$conditions,'fields'=>$fields)));
print_r($search_companies);die();
echo json_encode($search_companies);die();
With out seeing your data output, I am just going to take a stab at the problem.
Inside your $search_companies variable you are getting a multidimensional array probably with the other values of the other tables.
Why not just select the one array:
$wantedData = $search_companies['Company'];
// The key Company (which is the model) should be the data you are wanting.
Try setting model's recursive value to -1
$this->Company->recursive = -1;
$search_companies = $this->Company->find('first',
compact(array('conditions'=>$conditions,'fields'=>$fields)));
With this you will not fire the joins queries and therefore you only retrieve model's information.
Cakephp provide this functionality that we can unblind few/all associations on a any model. the keyword unbindModel is used for this purpose. inside the unblindModel you can define the association type and model(s) name that you want to unblind for that specific association.
$this->CurrentModelName->unbindModel(array('AssociationName' => array('ModelName_Youwwant_unblind')));

Recognize laravel's relationships

I got 3 linked tables and i am quite lost with eloquent relationship.
I need help to recognize my relationship type. I use Laravel 4.1
acquisitions table :
#id
date
sensors table :
#id
name
acquisition_sensor table:
#id
acquisition_id
sensor_id
depth
value
Indeed 1 acquisition may have many depth, and different values.
I search a way to link my tables and use sensor model likee:
Sensor::find(1)->acquisitions->count();
and
Sensor::find(1)->sensor_acquisition->get();
I actually do it with the Query Builder but i think there is a way to use it more efficiently with eloquent !
You are going to want to set up a many-to-many relationship in your Eloquent models.
Sensor.php (model)
public function acquisitions()
{
return $this->belongsToMany('Acquisition', 'acquisition_sensor', 'acquisition_id', 'sensor_id');
}
Acquisition.php (modal)
public function sensors()
{
return $this->belongsToMany('Sensor', 'acquisition_sensor', 'acquisition_id', 'sensor_id');
}
You can read more about many-to-many Eloquent relationships here, http://laravel.com/docs/eloquent#many-to-many
If you want to run the eloquent query you described in your question, then you can do it like so:
Sensor::find(1)->acquisitions()->count();
If you are chaining, then make sure to add the () to acquisitions.

Trying to restrict an Eloquent query to a relationship with a count of 0

I have two models (Organizations and Interactions) and I'd like to query the Organization model for all of the Orgs that have no Interactions. Organizations have a one-to-many relationship with Interactions.
I tried looking into anti-joins in raw SQL, but got nowhere. I also wanted to totally avoid anything like getting all of the full Organizations, then iterating through them to check to see if they had any Interactions, because that's completely impractical given the amount of data I'm working with.
To clarify, I want to avoid this:
$organizations = Organization::all();
foreach ($organizations as $org)
if($org->interactions()->count() == 0){
//Add the org to an array for later use because it has no interactions
}
I'm using Laravel 3.x, and I can't upgrade because the project is really big and I don't have the month it would take to upgrade to 4.1 right now. If there's a significantly better way to do stuff like this 4, that would make selling the conversion process easier.
Here's some relevant code:
//From organization.php
public function interactions() {
return $this->has_many('Interaction');
}
//From interaction.php
public function organization() {
return $this->belongs_to('Organization');
}
// select all Organization IDs that have at least 1 interaction
$uniqueOrganizationIDs = DB::raw('SELECT organization_id FROM interactions GROUP BY(organization_id)');
// Select orgs that were not in the above list.
Organization::whereNotIn('id', $uniqueOrganizationIDs)->get();
This is the solution I came up with:
Query the Organization and Interaction models using list(). For Orgs, get their ID. For Interactions, get their organization_id. I figure these are two low-footprint, fast queries.
Do an array_diff() on them to get an array of Organizations that don't have Interactions.
Query Organization using where_in(), feeding it the diff'ed array.
It looks like this:
$organizationIDs = DB::table('organizations')->where('is_deleted', '=', 0)->lists('id');
$interactionIDs = DB::table('interactions')where('is_deleted', '=', 0)->lists('organization_id');
$uncontactedOrganizationIDs = array_diff($organizationIDs, $interactionIDs);
$uncontactedOrganizations = Organization::where_in('id', $uncontactedOrganizationIDs)->order_by('created_at', 'DESC')->get();
Is there a better way to do this? I feel like there has to be.

Update object in the Entity framework that have relations

I am trying to update an whole entity object with relations in database in entity framework , and without success.
I am trying to do something like this:
var objectToUpdate = DAL.GetProduct(id);
// then I have collection of Comments related to this product.
// and I want to update th whole collection
objectToUpdate.Comments.Clear();
foreach(var newComment in comments){
objectToUpdate.Comments.Add(newComment);
}
What I am getting in database is duplication of all related to my products comments.
Please suggest how to update related Entities properly.
Thanks.
If you want to update a relationship between objectToUpdate and a collection of comments which are already existing in the database you need to attach the comments to context before you add them to the Comments collection of your objectToUpdate. Otherwise EF will create new comment rows in the database:
var objectToUpdate = DAL.GetProduct(id);
objectToUpdate.Comments.Clear();
foreach(var newComment in comments)
{
context.Comments.Attach(newComment);
objectToUpdate.Comments.Add(newComment);
}