I'm not sure, how this is called, so I'll explain it as good as possible.
I've a ticket system, where I display all comments in one section. In a different section, I display related information like "Supporter changed", "Ticket title changed", "Status of ticket changed" and so on.
Current rendered (unstyled) HTML: https://jsfiddle.net/2afzxhd8/
I would like to merge these two sections into one, that those related information are displayed between the comments of the ticket. Everything (comments + related information) should be displayed sorted based on the created_at
timestamp.
New target rendered (unstyled) HTML: https://jsfiddle.net/4osL9k0n/
The ticket system has in my case these relevant eloquent models (and tables):
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Tickets extends Model
{
use SoftDeletes;
protected $fillable = [
'tracking_number', 'customer_id', 'category_id',
'priority_id', 'subject', 'status_id', 'is_done',
'supporter_id'
];
protected $hidden = [
];
protected $dates = ['deleted_at'];
public function status() {
return $this->belongsTo(TicketStatuses::class, 'status_id');
}
public function priority() {
return $this->belongsTo(TicketPriorities::class, 'priority_id');
}
public function category() {
return $this->belongsTo(TicketCategories::class, 'category_id');
}
public function supporter() {
return $this->belongsTo(User::class, 'supporter_id');
}
public function operations() {
return $this->hasMany(TicketOperations::class, 'ticket_id');
}
public function comments() {
return $this->hasMany(TicketComments::class, 'ticket_id');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class TicketComments extends Model
{
use SoftDeletes;
protected $fillable = [
'ticket_id', 'text', 'user_id', 'is_html',
'email_reply', 'internal_only'
];
protected $hidden = [
];
protected $dates = ['deleted_at'];
public function ticket() {
return $this->belongsTo(Tickets::class, 'id', 'ticket_id');
}
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class TicketOperations extends Model
{
use SoftDeletes;
protected $fillable = [
'ticket_id', 'user_id', 'ticket_activity_id',
'old_value', 'new_value'
];
protected $hidden = [
];
protected $dates = ['deleted_at'];
public function ticket() {
return $this->belongsTo(Tickets::class, 'ticket_id');
}
public function activity() {
return $this->belongsTo(TicketActivities::class, 'ticket_activity_id');
}
public function user() {
return $this->belongsTo(User::class, 'user_id');
}
}
Please don't care about the CSS - it is styled in my case. It's just not relevant here.
Any idea, how I need to update my view to be able to build my target HTML?
As per my understanding, you have data that retrieved from multiple models.
So what you can do is to, merge the informations into a new array:
For example, consider the data regarding the ticket history is being stored in an array named:
$arrTicketHistory;
And consider, that the information regarding the ticket updates is being stored in an array named:
$arrTicketUpdates;
Merge these two arrays and assign the result in another array, say:
$arrDatesAndIDs;
Now try sorting the array $arrDatesAndIDs on the basis of timestamp i.e. created_at. Then display the result with a simple for loop.
You can add a custom parameter in the arrays $arrTicketUpdates and $arrDatesAndIDs, just for the sake of uniqueness. It might help you to identify which type of information it is, regarding the ticket.
You can use the array function array_msort(), a php function, to sort a multidimensional array.
I just found this answer, but this one has one big issue: It overwrites in worst-case some objects with different objects and this results in possible missing objects in the collection.
From the Laravel documentation: Collections:
The
merge
method merges the given array or collection with the original collection. If a string key in the given items matches a string key in the original collection, the given items's value will overwrite the value in the original collection.
Due to this, I had to update the logic to this:
$ticket = Tickets::where('tracking_number', '=', $request->tracking_number)->first();
$comments = $ticket->comments;
$operations = $ticket->operations;
$history_unsorted = new Collection();
$history_unsorted = $history_unsorted->merge($comments);
$history_unsorted = $history_unsorted->merge($operations);
$history = $history_unsorted->sortBy('created_at');
This avoids, that the original collection gets overwritten.
With this, I can simply loop over $history
:
@foreach($history as $history_item)
@if ($history_item instanceof App\TicketOperations)
<!-- Ticket Operation -->
@else
<!-- Ticket Comment (Text) -->
@endif
@endforeach
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With