#StackBounty: #php #eloquent Eloquent pivot table with different column name

Bounty: 50

Users table

- id
- name (string)

Visits table

- id
- user_id
- viewer_id 

I want to get a list of visits with the linked username for a given user (in this case id = 1)

$visits = Visits::where(['user_id' => 1])->with('user')->get();

this is my visits model:

class Visits extends Model
{

    protected $table = 'visits';

    public function store(Request $request)
    {
        $visits = new Visits;
        $visits->save();
    }

    public function user()
    {
        return $this->belongsTo('User', 'viewer_id');
    }

}

this is my User model

use IlluminateDatabaseEloquentModel;

class User extends Model
{

public function store(Request $request)
{
    $user = new User;
    $user->save();
}

}

it returns the data but the “user” is null


Get this bounty!!!

#StackBounty: #php #laravel #eloquent PHP Laravel – Improving and refactoring code to Reduce Queries

Bounty: 50

Improve Request to Reduce Queries

I have a web application, where users can upload Documents or Emails, to what I call a Strema. The users can then define document fields email fields to the stream, that each document/email will inherit. The users can then furthermore apply parsing rules to these fields, that each document/email will be parsed after.

Now let’s take the example, that an user uploads a new document. (I have hardcoded the ID’s for simplicty).

$stream = Stream::find(1);
$document = Document::find(2);

$parsing = new ApplyParsingRules;
$document->storeContent($parsing->parse($stream, $document));

Below is the function that parses the document according to the parsing rules:

    public function parse(Stream $stream, DataTypeInterface $data) : array
    {
        //Get the rules.
        $rules = $data->rules();

        $result = [];
        foreach ($rules as $rule) {

            $result[] = [
                'field_rule_id' => $rule->id,
                'content' => 'something something',
                'typeable_id' => $data->id,
            ];
        }

        return $result;
    }

So above basically just returns an array of the parsed text.

Now as you probably can see, I use an interface $DataTypeInterface. This is because the parse function can accept both Documents and Emails.

To get the rules, I use this code:

//Get the rules.
$rules = $data->rules();

The method looks like this:

class Document extends Model implements DataTypeInterface
{
    public function stream()
    {
        return $this->belongsTo(Stream::class);
    }
    public function rules() : object
    {
        return FieldRule::where([
            ['stream_id', '=', $this->stream->id],
            ['fieldable_type', '=', 'AppDocumentField'],
        ])->get();
    }
}

This will query the database, for all the rules that is associated with Document Fields and the fields, that is associated with the specific Stream.

Last, in my first request, I had this:

$document->storeContent($parsing->parse($stream, $document));

The storeContent method looks like this:

class Document extends Model implements DataTypeInterface
{
    // A document will have many field rule results.
    public function results()
    {
        return $this->morphMany(FieldRuleResult::class, 'typeable');
    }
    // Persist the parsed content to the database.
    public function storeContent(array $parsed) : object
    {
        foreach ($parsed as $parse) {
            $this->results()->updateOrCreate(
                [
                    'field_rule_id' => $parse['field_rule_id'],
                    'typeable_id' => $parse['typeable_id'],
                ],
                $parse
            );
        }
        return $this;
    }
}

As you can probably imagine, everytime a document gets parsed, it will create be parsed by some specific rules. These rules will all generate a result, thus I am saving each result in the database, using the storeContent method.

However, this will also generate a query for each result.

One thing to note: I am using the updateOrCreate method to store the field results, because I only want to persist new results to the database. All results where the content was just updated, I want to update the existing row in the database.

For reference, above request generates below 8 queries:

select * from `streams` where `streams`.`id` = ? limit 1
select * from `documents` where `documents`.`id` = ? limit 1
select * from `streams` where `streams`.`id` = ? limit 1    
select * from `field_rules` where (`stream_id` = ? and `fieldable_type` = ?)
select * from `field_rule_results` where `field_rule_results`.`typeable_id` = ? and...
select * from `field_rule_results` where `field_rule_results`.`typeable_id` = ? and...  
insert into `field_rule_results` (`field_rule_id`, `typeable_id`, `typeable_type`, `content`, `updated_at`, `created_at`) values (..)
insert into `field_rule_results` (`field_rule_id`, `typeable_id`, `typeable_type`, `content`, `updated_at`, `created_at`) values (..)

Above works fine – but seems a bit heavy, and I can imagine once my users starts to generate a lot of rules/results, this will be a problem.

Is there any way that I can optimize/refactor above setup?


Get this bounty!!!

#StackBounty: #php #laravel #eloquent Updating one-to-many relationships with updateOrCreate methods

Bounty: 50

My main model Tag has a one-to-many relationship with Product where one Tag can have many Products assigned to them via tag_id relationship on the DB.

On my edit view, I am allowing users to edit the tag products. These products can be added/edited/deleted on the form request.

Each product field on the form is picked up from a request() array. E.g: request('title'),request('price').

I have set $title[$key] as the request('title') array for example.

My thoughts next, was to loop through each of the products for this tag and updateOrCreate based on the request data. The issue here, is that there’s no way of detecting if that particular product was indeed needing updated.

TagController – Update Product Model (One-to-Many)

foreach($tag->products as $key => $product){

  Product::updateOrCreate([
   'id'  => $product->id,
   ],
     [
       'title' => $title[$key],
       'price' => $price[$key],
       'detail' => $detail[$key],
       'order' => $order[$key],
       'tagX' => $tagX[$key],
       'tagY' => $tagY[$key],
       'thumb' => $img[$key],
   ]);
}

For the initial tag update, I have set an if statement which works great (albeit messy) for the main tag img.

TagController – Update Tag Model

//Update the tag collection
if($request->hasFile('img')) {
  $tag->update([
    'name' => $name,
    'hashtag' => $hashtag,
    'img' => $imgPub,
  ]);
} else{
  $tag->update([
    'name' => $name,
    'hashtag' => $hashtag,
  ]);
}

Is there a better way to determine if the product fields were updated on the request?

Ideally I would like the user to be able to add/remove or edit products from the tag edit request, but not delete existing product images if they have not been updated. Thanks!


Get this bounty!!!