Difference between all() and toArray() in Laravel 5 - arrays

When I manage a collection that I need to convert to an array, I usually use toArray(). But I can also use all(). I'm not aware of the diference of those 2 function...
Anybody knows?

If it's a collection of Eloquent models, the models will also be converted to arrays with toArray()
$col->toArray();
With all it will return an array of Eloquent models without converting them to arrays.
$col->all();
The toArray method converts the collection into a plain PHP array. If the collection's values are Eloquent models, the models will also be converted to arrays:
toArray()
all() returns the items in the collection
/**
* Get all of the items in the collection.
*
* #return array
*/
public function all()
{
return $this->items;
}
toArray() returns the items of the collection and converts them to arrays if Arrayable:
/**
* Get the collection of items as a plain array.
*
* #return array
*/
public function toArray()
{
return array_map(function ($value) {
return $value instanceof Arrayable ? $value->toArray() : $value;
}, $this->items);
}
For example: Grab all your users from database like this:
$users = User::all();
Then dump them each way and you will see difference:
dd($users->all());
And with toArray()
dd($users->toArray());

Related

Sorting a Doctrine ArrayCollection by a specific, custom field

I am attempting to sort an ArrayCollection by a specific field. The ArrayCollection is an array of courses. In the Course entity there is a method called isLive which returns a boolean.
I would like to sort this collection to have the "live" courses at the beginning of the array, so that's the courses that return true from a isLive call.
This is the code I have at present, but the first entry in the $sorted array is a non-live course.
$iterator = $this->courses->getIterator();
$iterator->uasort(function ($a, $b) {
if ($a->isLive() == $b->isLive()) {
return 0;
}
return ($a->isLive() < $b->isLive()) ? -1 : 1;
});
$sorted = new ArrayCollection(iterator_to_array($iterator));
It looks like a good use case for Doctrine Criteria. They allow to filter/sort ArrayCollections, either in memory if the collection is already loaded, either by adding a WHERE / ORDER BY SQL clause next time the collection will be loaded from the database. So that's pretty optimized!
Code should look like something like this, assuming you have a live field behind isLive():
$criteria = Criteria::create()
->orderBy(["live" => Criteria::DESC])
;
$sorted = $this->courses->matching($criteria);
For the entity, do this: add an OrderBy annotation to the property.
/**
* #OneToMany(targetEntity="Course")
* #OrderBy({"live": "ASC"})
*/
private $courses;
I got to a solution with the use of uasort and array_search as below:
/**
* #return ArrayCollection
*/
public function getCoursesSortedByLive(): ArrayCollection
{
$coursesIterator = $this->courses->getIterator();
$sortOrder = [true];
$coursesIterator->uasort(function ($a, $b) use ($sortOrder) {
return array_search($a->isLive(), $sortOrder) - array_search($b->isLive(), $sortOrder);
});
return new ArrayCollection(iterator_to_array($sitesIterator));
}

How do I paginate a collection or custom query into API json in Laravel?

I have a complex query that is not based on any specific model table that I want to paginate output for. However laravel's built in pagination relies on models and tables. How can I paginate a collection and have the output match up with laravel's built in pagination output format?
I keep this in an app\Core\Helpers class so that I can call them from anywhere as \App\Core\Helpers::makePaginatorForCollection($query_results). The most likely place to use this is the last line of a controller that deals with complex queries.
In app/Http/Controllers/simpleExampleController.php
/**
* simpleExampleController
**/
public function myWeirdData(Request $request){
$my_unsafe_sql = '...';//never do this!!
$result = DB::statement(DB::raw($my_unsafe_sql));
return \App\Core\Helpers::makePaginatorForCollection($result);
}
In app\Core\Helpers.php or anywhere you like that auto loads.
/**
* This will match laravel's built in Model::paginate()
* because it uses the same underlying code.
*
* #param \Illuminate\Support\Collection $collection
*
* #return \Illuminate\Pagination\LengthAwarePaginator
*/
public static function makePaginatorForCollection(\Illuminate\Support\Collection $collection){
$current_page = (request()->has('page')? request()->page : 1) -1;//off by 1 (make zero start)
$per_page = (request()->has('per_page')? request()->per_page : config('api.pagination.per_page')) *1;//make numeric
$page_data = $collection->slice($current_page * $per_page, $per_page)->all();
return new \Illuminate\Pagination\LengthAwarePaginator(array_values($page_data), count($collection), $per_page);
}
/**
* Copy and refactor makePaginatorForCollection()
* if collection building is too slow.
*
* #param $array
*
* #return \Illuminate\Pagination\LengthAwarePaginator
*/
public static function makePaginatorForArray($array){
$collection = collect($array);
return self::makePaginatorForCollection($collection);
}

CakePHP 3 - Easiest way to retrieve a single field from the database

In CakePHP 2 I could do something like this:
$name = $this->User->field('name', ['email' => 'user#example.com']);
In CakePHP 3 you have to do something like this to achieve the same thing:
$users = TableRegistry::get('Users');
$query = $users->find()
->select('name')
->where(['email' => 'user#example.com']);
$name = $query->isEmpty() ? null : $query->first()->name;
Is there a simpler way to perform these kinds of operations? I'm not very familiar with the new ORM.
Edit: I have added an example of a class which adds this behavior for Cake 3:
https://stackoverflow.com/a/42136955/851885
It's possible to add this functionality to any Table via a custom behavior.
Save as src/Model/Behavior/EnhancedFinderBehavior.php
<?php
namespace App\Model\Behavior;
use Cake\ORM\Behavior;
/**
* EnhancedFinder behavior
*
* Behavior providing additional methods for retrieving data.
*/
class EnhancedFinderBehavior extends Behavior
{
/**
* Retrieve a single field value
*
* #param string $fieldName The name of the table field to retrieve.
* #param array $conditions An array of conditions for the find.
* #return mixed The value of the specified field from the first row of the result set.
*/
public function field($fieldName, array $conditions)
{
$field = $this->_table->getAlias() . '.' . $fieldName;
$query = $this->_table->find()->select($field)->where($conditions);
if ($query->isEmpty()) {
return null;
}
return $query->first()->{$fieldName};
}
}
Note: for CakePHP versions prior to 3.4, change the code to $this->_table->alias(), which was deprecated in favour of getAlias() in later versions.
Usage
Add the behavior to your class:
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class UsersTable extends Table
{
public function initialize(array $config)
{
$this->addBehavior('EnhancedFinder');
}
}
Now you can use the finder like Cake 2:
$name = $this->User->field('name', ['id' => 1]);
This might be simpler than yours
$users = TableRegistry::get('Users');
$name = $users->get(1)->name;
Make sure that when you use the get function, the parameter should be a primary key in the table.
No, there is not in CakePHP 3.x.
If you want that method back implement it either in a behavior or as a finder using a trait and use it with your table objects.

Calling shuffle on a filtered backbone collection

I'm trying to filter a Collection, and then shuffle the filtered values.
I was thinking of using the where method Backbone provides. Something like:
myRandomModel = #.where({ someAttribute: true }).shuffle()[0]
However, where returns an array of all the models which match the attributes; and apparently shuffle needs a list to work with:
shuffle_ .shuffle(list)
Returns a shuffled copy of the list
http://documentcloud.github.com/underscore/#shuffle
Is there a way to turn my array of models into a 'list'? Or should I write some logic myself to get this done?
When the Underscore docs say list, they mean array. So you can use _.shuffle like this:
shuffled = _([1, 2, 3, 4]).shuffle()
Or in your case:
_(#where(someAttribute: true)).shuffle()
However, since you're just grabbing a single model, you could simply generate a random index instead of shuffling:
matches = #where(someAttribute: true)
a_model = matches[Math.floor(Math.random() * matches.length)]
The shuffle() and where() method are just a proxy in Backbone collections to the underscore method. Underscore methods still work on their own, with arrays as argument. Here is what I would do:
myRandomModel = _.shuffle(#.where({ someAttribute: true }))[0]
Reference: http://documentcloud.github.com/underscore/#shuffle
PS: #"mu is too short" is right however, to get a single model I would go the Math.random() way myself.
I put the following in my application.js file (using Rails 3):
Array.prototype.shuffleArray = function() {
var i = this.length, j, tempi, tempj;
if ( i === 0 ) return false;
while ( --i ) {
j = Math.floor( Math.random() * ( i + 1 ) );
tempi = this[i];
tempj = this[j];
this[i] = tempj;
this[j] = tempi;
}
return this;
};
and now I can call shuffleArray() on an array of arrays. Leaving this unanswered for now though, since I would like to know if there is a better way to do it with Underscore/Backbone.
First in your collection you should have a filtered function
Like
var MyCollection = Backbone.Collection.extend ({
filtered : function ( ) {
Normally you will use _.filter to get only the models you wanted but you may also use the suffle as a replacement use this.models to get the collection models
Here shuffle will mix the models
var results = _ .shuffle( this.models ) ;
Then use underscore map your results and transform it to JSON
like so
results = _.map( results, function( model ) { return model.toJSON() } );
finally returning a new backbone collection with only results you may return only the json if that's what you are looking for
return new Backbone.Collection( results ) ;
note if you don't want to keep all data in collection for later uses you may use the following and ignore the view below ;
this.reset( results ) ;
}
});

drupal_write_record doesn't take object

In drupal 6 i used to do something like this:
<?php
/*
* CLASS Example
*/
class example {
var $id = NULL;
var $title;
var $body;
.....
// Save
function save() {
$primary_key = ($this->id == NULL ? NULL : 'id');
if (drupal_write_record('mytabble', $this, $primary_key)) {
return TRUE;
} else {
return FALSE;
}
}
}
?>
This worked quite well. But in Drupal 7, the drupal_write_record only takes an array and no longer the object $this. The new db_merge also only takes an array.
Since i want to save the properties of my object to the database, the above code was very handy and generic for all kinds of classes.
Is there an alternative way to write an object to database, or a method to place objectproperties into a an array?
Any help will be appreciated!
Robert
drupal_write_record does take an object or an array. Guess your problem is caused somewhere else.
drupal_write_record($table, &$record, $primary_keys = array())
$record: An object or array representing the record to write, passed in by reference. If inserting a new record, values not provided in $record will be populated in $record and in the database with the default values from the schema, as well as a single serial (auto-increment) field (if present). If updating an existing record, only provided values are updated in the database, and $record is not modified.
More info on drupal_write_record for D7.

Resources