get multiple docs by ID as ActiveRecord in Yii2 from ealstic search using mget() - elasticsearch

I'm using the Yii2 class yii\elasticsearch\ActiveRecord to recieve data from elastic search. Usually methods in this class for getting data from elastic will return that data as ActiveRecord (AR) object. So it's easy, to create an activeDataProvider from that AR to fill that data into a listview, etc.
But: yii\elasticsearch\ActiveRecord::mget() does not return an AR-object. Instead it return an array of documents.
My questions:
1.) Is there a way to use the mget - feature / elastic multi get feature AND get the result as AR object?
OR
2.) Is there a way to bring that array of documents into an AR object to make ActiveDataProvider including listview working?

I found the following solution:
Runnig Yii2 mget with an list of the ID's I like to get, which returns an array of docs.
Creating an ActiveDataProvider using ArrayDataProvider Class and the mget-output from step before
Example Code:
use app\models\MyModel;
use yii\data\ArrayDataProvider;
$ids = ['123','456','789'];
$myModel = new MyModel(); # Data Model based on yii\mongodb\ActiveRecord;
$result = $myModel->mget($ids); # get documents from elastic where document id is in $ids
$dataProvider = new ArrayDataProvider([
'allModels' => $result
]); # creating ActiveDataProvider, which can be used in Listviews.

Related

Laravel eloquent make visible only given attribute in one instance of model

i have instance model from
$model = Model::find(1);
for example this instance always return these attribute (some is from $append):
-id
-name
-countRelation
-description
-created_at
-updated_at
what i want is to only retrive name and description from this instance;
makeVisible only work to show hidden attribute; i don't want use makeHidden because the result of find may change if on model i add new append attribute;
Since you are appending accessors limiting the SELECT statement won't stop those from being appended to the serializied output. You can use setVisible to do this though:
$model->setVisible(['name', 'description']);
Setting what is visible this way will limit the attributes, appends and relationships that are returned in the serialized output of the Model.
You can use select to only retrieve some column in your database, it will not affect append, see the doc for more info Eloquent
$model = Model::find(1);
// to this
$model = Model::select('name', 'description')->find(1);
See Query Builder for more insight about grabbing data from database.
if you retrieve name and description only, then you may use
$model = Model::select(['name', 'description'])->find(1);
You can use select() to select only certain columns in your query.
$model = Model::select('name', 'description')->find(1);
https://laravel.com/docs/8.x/queries#specifying-a-select-clause
You can also get the Model and use functions on the model. If you have a single Model you can use get().
$model = Model::find(1)->get('name', 'description');
If you have a collection you can use ->map->only(). This maps the only function as a callback for each Model in your Collection.
$models = $models->map->only(['name', 'description']);

How can I get the data inside my notifications from within my Controller?

I'm trying to get the numbers of records from my notifications, where the candidate_user_id column from inside the data attribute is the same as the UserId (Authenticated User).
After I dd, I was able to get the data from all of the records in the table by using the pluck method (Line 1). I then tried to use the Where clause to get the items that I need
but this just didn't work, it was still returning all of the records in the table.
DashboardController.php:
public function index()
{
$notifications = Notification::all()->pluck('data');
$notifications->where('candidate_user_id', Auth::user()->id);
dd($notifications);
}
Here is a partial screenshot of the data that is being plucked.
How can I get the data from this, in a way like this ->where('candidate_user_id', Auth::user()->id);?
If data was a JSON field on the table you could try to use a where condition to search the JSON using the -> operator:
Notification::where('data->candidate_user_id', Auth::id())->pluck('data');
Assuming you only want this data field and not the rest of the fields, you can call pluck on the builder directly. There isn't much reason to hydrate Model instances with all the fields to then just pluck a single field from them if it is just a table field, so you can ask the database for just the field you want.
The data in the data field is a json string, so you can tell Laravel to automatically cast it as an array using the $casts property on each of the models that is notifiable.
For instance, if you have a User model which uses the trait (ie has use Notifiable), add this:
protected $casts = [
'data' => 'array',
];
If you want to access all notifications for the auth user.
$user = auth()->user();
dd($user->notifications->pluck('data'));
If you really want to do in your question way, here is how.
$notifications = Notification::all()->pluck('data');
$notifications = $notifications->where('candidate_user_id', Auth::user()->id)
->all();
This assumes you that you did not modify the default laravel notifications relationship and database migration setup. If you have modified some of the default ones, you need to provide how you modify it.

Laravel Backpack : Storing Belongs To Many relationships using custom view

I have a flight class and this flight has a custom view field like so:
This represents a belongs to many relationship which stores website_id / flight_id and pricing as pivot data in a pivot table.
The custom view uses JS to send this data back to the controller in this format:
{"1":{"price_adult":"434","price_child":"545"},"2":{"price_adult":"323","price_child":"324"},"3":{"price_adult":"434","price_child":"43"}}
Trying to send this data with the request doesn't create the relations fields, and because I do not have a flight ID at the point of creating this within the controller I can not loop this JSON to make the relations manually.
Can anyone point out what the best course of action is or if there is support for this? I took a look at the docs but they are woefully short and patchy in terms of being much help.
EDIT:
I should have said I can probably make this work using a custom name attribute on the model for the relation, then add a set mutator to loop this data and update the prices relation but I don't want to go down this route if there is support for this I am missing out of the box in backpack.
EDIT2:
Someone asked about the relation:
$this->belongsToMany(Website::class, 'website_pricing')->withPivot('price_adult', 'price_child');
This is working fine its not a problem with the relation working its how can I get backpack to store the data as a relation when the flight has no ID yet, or how can I pass the data I posted above in such a way that the backpack crud controller can handle it?
You may need to create a flight first, if no flight id is being provided. Can you explain the database relational structure more?
Basically thought I should post what I did because no one could provide an answer to this.
So basically you have to copy the store / update functions from the parent, changing a few lines.
$this->crud->hasAccessOrFail('create');
// fallback to global request instance
if (is_null($request)) {
$request = \Request::instance();
}
// replace empty values with NULL, so that it will work with MySQL strict mode on
foreach ($request->input() as $key => $value) {
if (empty($value) && $value !== '0') {
$request->request->set($key, null);
}
}
// insert item in the db
$item = $this->crud->create($request->except(['save_action', '_token', '_method']));
$this->data['entry'] = $this->crud->entry = $item;
// show a success message
\Alert::success(trans('backpack::crud.insert_success'))->flash();
// save the redirect choice for next time
parent::setSaveAction();
return parent::performSaveAction($item->getKey());
Basically any line which references a function in the parent class using $this->method needs to be changed to parent::
This line is what I used to submit the relations JSON string passed to the controller as relations $item->prices()->sync(json_decode($request->input('prices'), true));
This is done after the line containing $item = $this->crud->create as the item id that just got stored will be available at that point.

Convert Laravel Query builder to Eloquent builder

Because get() function of Query builder returns an array while I need A collection, is there a way to convert Laravel Query Builder to Eloquent Builder?
$query_builder = DB::table('table1');
// different than
$eloquent_builder = Table1Model::select()
Laravel ships with a collect helper to convert an array to a collection:
$collection = collect(DB::table('table1')->get());
There's a proposal on Github to have the next version of Laravel return collection instances from the query builder's get method.

Laravel Eloquent: inserting data

I am sending a bunch of data through post method. For now I am using a fully working solution:
$dataClient = new Client;
$dataClient->name = $post['client']['name'];
$dataClient->address = $post['client']['address'];
...
$dataClient->save();
I am wondering if there is a shorter solution? Like posting an array and Laravel could map keys to db fields?
What if you would add something more, like calculated value upon?
Example:
$dataClient = new Client;
Then map array keys to db keys
$dataClient->someField = someCalculatedValue
$dataClient->save();
Thank you in advance.
You have quite a few options when it comes to creating models from a data array. If you want to directly insert it into the database, the easiest way is create()
Client::create($post['client']);
If you want to change some things afterwards or just not save it right away, just pass your data to the constructor.
$client = new Client($post['client']);
$client->someField = 'some value';
$client->save();
And finally, the last option, calling fill() manually. This method is used internally for create() as well as in the constructor.
$client = new Client();
$client->fill($post['client']);
$client->save();
Note: for all methods above you'll need to set up the fillable attributes in your model. This is to protect against malicious user input (request data).
protected $fillable = ['name', 'address', 'etc'];
More information about Mass Assignment
Eloquent has create and update methods which will insert massive data. For example :
inputs = ['name' => 'value','address' => 'value'];
Client::create(inputs)
It will automatically map fields in Eloquent.
Have you tried something like this?
$dataClient = new Client;
$dataClient->fill($client);
$dataClient->save();
Depending on how you set up your Client model and what fields you set as guarded/fillable, the fill method will automatically map the data with their respective fields.

Resources