#StackBounty: #mysql #laravel #eloquent #mariadb Laravel Eloquent order by field as 1,2,3,4,1,2,3,4

Bounty: 250

I have goods table

good_link, parent_link, name
sdf-sdfg   ffff         rock    
utyruuur   ffff         qwe     
gfhdfggg   dddd         paper   
sdfghvcx   eeee         water   
ncvbcxvb   dddd         tree    
dsgfdsg    zzzz         sdff
sdfsdff    zzzz         fdgdf
sdfgdgg    zzzz         sdfsdf
dsvfdgg    zzzz         ssdfgr
brtyfgh    zzzz         fgdfgdf

How can I order data by parent_link to have data like

ffff
dddd
eeee
zzzz
ffff
dddd
zzzz
zzzz
zzzz
zzzz

so all goods goes one after another but always with different parent_link(previous row parent_link != next row parent_link, and ordering A-Z has no difference)?


Get this bounty!!!

#StackBounty: #laravel #eloquent Laravel Polymorphic belongsToThrough

Bounty: 200

I have there tables:

// Itinerary
id

// Location
id

// Popup
id

// Poi
id
itinerary_id
poiable_id
poiable_type

// Hotspot
id
content_id
content_type

A Itinerary hasMany Locations and Popups through POI (poiable, polymorphic)

class Itinerary extends Model {
...
  public function pois()
  {
    return $this->hasMany('AppModelsPoi');
  }

  public function popups()
  {
    return $this->morphedByMany('AppModelsPopup', 'poiable', 'poi');
  }

  public function locations()
  {
    return $this->morphedByMany('AppModelsLocation', 'poiable', 'poi');
  }
}

Locations and Popups hasMany Hotspots (polymorphic via content_id, content_type). A Hotspot holds coords. A location or popup can be opened from multiple angles in an itinerary but holds the same information.

itinerary -> poi -> location or popup -> hotspot

What I’m trying to do is to return all the hotspots of an itinerary, it must be a Relation to keep existing code intact.

Something in the line of:

function hotspots() {
return $this->hasManyThrough('AppModelsHotspot', 'AppModelsPoi', 'itinerary_id', 'content_id', 'id', 'poiable_id')->join('poi', 'hotspot.content_type', '=', 'poi.poiable_type')
}

but can’t get it to work (Syntax error or access violation: 1066 Not unique table/alias:)


Get this bounty!!!

#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!!!