this is laravel 5.3
when I preview the email using this:
$wantsheet_products = WantsheetProduct::orderByRaw(EmailService::WANTSHEET_PRODUCT_ORDER_SQL)->get();
View::make('email.wantsheet.email_wantsheet_to_supplier', ['wantsheet_products' => $wantsheet_products]);
the sorting is correct. that is, sorting is ['a','b','c'] the way i want it.
EDIT see note at the bottom
now when actually sending out the mails (i queue them), the sorting changed and is unsorted again, magic?! the change happens between the constructor and the build function
class WantsheetToSuppliersMail extends Mailable
{
public $wantsheet_products;
public $to_email;
/** @var WantsheetContact $wantsheetcontact*/
public $wantsheetcontact;
use Queueable, SerializesModels;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct($wantsheet_products)
{
//$wantsheet_products is a standard eloquent model collection, e.g. i get it like this: WantsheetProduct::orderByRaw(self::WANTSHEET_PRODUCT_ORDER_SQL)->get()
$this->wantsheet_products = $wantsheet_products; //is ['a','b','c']
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
// $this->wantsheet_products is ['b','a','c'];
$subject = 'abc';
return $this->from('me@myapp.com')->view('email.wantsheet.email_wantsheet_to_supplier', [])->subject($subject);
}
}
EDIT contd. Now when i do
WantsheetProduct::orderByRaw(EmailService::WANTSHEET_PRODUCT_ORDER_SQL)->get()->toArray();
it doesn't break the sorting any longer (so it works). But that is stupid, isn't it?
When your mail object is queued for delivery, it takes your Collection
of Model
instances, gets their ids, and stores the list of ids on the queued job. When the queued job is then processed, it takes those Model ids, and retrieves the data from the database.
The problem, however, is that the query being run to rebuild the collection doesn't care about the order of the ids. It just runs a whereIn()
statement with the list of ids.
Everything worked when you converted your Collection toArray()
because it also converted all your Models to arrays. So, it was no longer a Collection of Models, it was an array of arrays. There is no special serialization that takes place there, so the data went across exactly as you sent it.
The easiest way to get your order back is probably to override the restoreCollection
method, so you can add in your order by clause to the restoration query. Add this method to your WantsheetToSuppliersMail
class:
protected function restoreCollection($value)
{
if (! $value->class || count($value->id) === 0) {
return new EloquentCollection;
}
$model = new $value->class;
return $model->newQuery()->useWritePdo()
->whereIn($model->getKeyName(), $value->id)
->orderByRaw(EmailService::WANTSHEET_PRODUCT_ORDER_SQL)
->get();
}
This is the same as the current function, just that your custom order by has been applied to the query.
it is a known bug of laravel 5.3
basically reretrieve the objects in the build function e.g.
public function build()
{
$this->wantsheet_products = WantsheetProduct::orderByRaw(EmailService::WANTSHEET_PRODUCT_ORDER_SQL)->get();
$subject = 'abc';
return $this->from('me@myapp.com')->view('email.wantsheet.email_wantsheet_to_supplier', [])->subject($subject);
}