I have mysql table 'test' with three columns,
1.sno 2.name 4.country
this code is easily understandable
$person = \App\Test::find(1);
$person->country; //Defined in Test eloquent model
now i want to do something like this:
$p = ['sno' => 1, 'name' => 'Joe', 'country' => '1' ];
$p->country; //Return relevent column form countries table as defined in Model
The thing to remember is that the user i am trying to map is already present in the database table. How to i convert an array to eloquent model?
You could instantiate the model class with no attributes:
$dummy = new \App\Test;
Then you can call the newInstance() method:
$attributes = ['sno' => 1, 'name' => 'Joe', 'country' => '1' ];
$desiredResult = $dummy->newInstance($attributes, true);
The true flag in the method is telling eloquent that the instance already exists in database, so you can continue working with it normally. Now you can do:
$desiredResult->country //'1'
Related
I want to insert multiple rows in a table, where the data collection I am inserting has a unique number. For example : I am inserting 2 row for a user_id number 1. My codes from controller is : I want to keep DB::table() instead of laravel eloquent
foreach($post_data['user_id'] as $key => $no){
$set_base = DB::table('package_user')
->Insert([
'base_id' => $post_data['base_id'],
'base_title' => $post_data['base_title'],
'user_id' => $no,
'package_id' => $post_data['package_id'],
'plan_id' => $post_data['plan_id'],
'currency' => $post_data['currency'],
'payable_plan_amount' => $post_data['total_amount'],
'created_at' => Carbon::now()
]);
}
Please refer How to insert multiple rows from a single query using eloquent/fluent there is a solution for both eloquent and querybuilder
$data = [
['user_id'=>'Coder 1', 'subject_id'=> 4096],
['user_id'=>'Coder 2', 'subject_id'=> 2048],
];
Model::insert($data); // Eloquent approach
DB::table('table')->insert($data); // Query Builder approach
You can also use fill() method if the model instance already created with the pre-defined populated datas.
<code>
$modelObj = new Model();
$modelCollection = collect($request->input())->all();
$modelObj->fill($modelCollection);
$modelObj->save();
</code>
I want to populate a table with listings of car offers with dummy data.
The specific is that I want the make and model to be from a table already created in the database. Also the listing's title to be Make and Model. My code is this, but I assume it is totally wrong:
public function definition()
{
$id = DB::table('cars')->select('id')->inRandomOrder()->first();
$make = DB::table('cars')->where('id', $id)->select('make')->first();
$model = DB::table('cars')->where('id', $id)->select('model')->first();
return [
'title' => $make . " " . $model,
'make' => $make,
'model' => $model,
'year' => $this->faker->numberBetween(1950, 2021),
'slug' => $this->faker->word(),
];
}
The query builder in Laravel returns an object representing the database model when you fetch with first()
You should access the attributes when you're setting them as other model attributes
return [
'title' => $make->make . " " . $model->model,
'make' => $make->make,
'model' => $model->model,
'year' => $this->faker->numberBetween(1950, 2021),
'slug' => $this->faker->word(),
];
Note
The answer above only fixes the issue in the current code
The correct implementation would be to create models (if don't exist already) and link them with relationships through foreign keys and then attach them together in a seeder
The factory should only contain a clear and clean definition of fake data
I'm building an audit system in my application, and I want to compare an Eloquent Model attribute changes after save() method. Here's an example of what I need:
$person = Person::find(1); //Original data: $person->name -> 'Original name', $person->age -> 22
$person->name = 'A new name';
$person->age = 23;
$person->save();
//At this point, I need to get an array like this (only with the attributes that have changed):
[
'age' => ['old' => 22, 'new' => 23],
'name' => ['old' => 'Original name', 'new' => 'A new name']
]
I know Eloquent already has some functions like isDirty(), getDirty() and getChanges(), however this methods only return the new values, and I need to get the old and the new values to store in my audit table.
Is there any way to do this without need to "clone" my variables and then compare it to get the changes?
Before saving your model you can access the original (old) attribute values like:
$person->original.
Furthermore you can call: $person->getChanges() to get all attributes that changed.
Before the Save() function and before overwriting the variables on lines 2 and 3, you can get old data by doing this:
$oldName = $person->name;
$oldAge = $person->age;
And then, after saving, you can insert your values in an array, like this:
$values = array(
"oldName" => $oldName,
"newName" => "New Name",
"oldAge" => $oldAge,
"newAge" => "New Age",
);
So you can get values from the array by doing:
echo $values["oldName"];
echo $values["newAge"];
...
You can clone the newly retrieved model before making the changes.
Something along the line of
$person = Person::find(1);
$original_person = cone $person;
// update the person object
// ...
$person->save();
You can proceed to construct your array like so:
[
'age' => ['old' => $original_person->age, 'new' => $person->age],
'name' => ['old' => $original_person->name, 'new' => $person->name]
]
You can do this within updated() boot function in the model class
class Mymodel extends Model
{
public static function boot()
{
parent::boot();
self::updated(function ($model) {
var_dump($model->original);
var_dump($model->getChanges());
// Traverse the changed array and save with original values
});
}
}
Im trying to save data inside a pivot table with an extra field called data.
when i save i have this array:
[
5 => "files"
4 => "pictures"
3 => "tags"
1 => "thumbs"
]
My table looks like this:
project_id
option_id
name
The ids shown above refer to option_id and the string to name inside the database.
When i try to use sync like this: $project->options()->sync($data);
$data is the array shown above
Im getting a error thats its trying to save the option_id with "files".
Here is how i build up the data that i use for sync:
Im trying to get what you suggested but dont know how to achieve it:
here is how i build up the array:
foreach($request->input('option_id') as $id) {
$option['option_id'][] = $id;
$option['data'][] = $request->input('data')[$id];
}
$data = array_combine($option['option_id'], $option['data']);
This is covered in the manual:
Adding Pivot Data When Syncing
You may also associate other pivot table values with the given IDs:
$user->roles()->sync(array(1 => array('expires' => true)));
In your example, you would have to change your array to look something like below but I believe this would translate to:
$data = [
5 => [ 'name' => "files" ],
4 => [ 'name' => "pictures" ],
3 => [ 'name' => "tags" ],
1 => [ 'name' => "thumbs" ],
];
$project->options()->sync($data);
I believe you may also need to modify how your Project model relates itself to your Options model:
// File: app/model/Project.php
public function options()
{
return $this->belongsToMany('Option')->withPivot('name');
}
This is also noted in the linked-to manual page:
By default, only the keys will be present on the pivot object. If your pivot table contains extra attributes, you must specify them when defining the relationship.
Update
Try creating your $data array like this:
$data = [];
foreach($request->input('option_id') as $id) {
$data[$id] = [ 'name' => $request->input('data')[$id] ];
}
Is it possible to access more than one model deep in a relationship in Lithium?
For example, I have a User model:
class Users extends \lithium\data\Model {
public $validates = array();
public $belongsTo = array("City");
}
and I have a City model:
class Cities extends \lithium\data\Model {
public $validates = array();
public $belongsTo = array("State");
}
and a State model, and so on.
If I'm querying for a User, with something similar to Users::first(), is it possible to get all the relationships included with the results? I know I can do Users::first(array('with' => 'City')) but I'd like to have each City return its State model, too, so I can access it like this:
$user->city->state->field
Right now I can only get it to go one deep ($user->city) and I'd have to requery again, which seems inefficient.
Using a recent master you can use the following nested notation:
Users::all( array(
'with' => array(
'Cities.States'
)
));
It will do the JOINs for you.
I am guessing you are using SQL?
Lithium is mainly designed for noSQL db´s, so recursiveness / multi joins are not a design goal.
You could set up a native sql join query and cast it on a model.
query the city with Users and State as joins.
you could setup a db based join view and li3 is using it as a seperate model.
you probably should split your planned recursive call into more than one db requests.
Think about the quotient of n Cities to m States. => fetch the user with city and then the state by the state id. => pass that as two keys or embed the state info. This would be acceptable for Users::all() queries aswell.
Example using Lithiums util\Set Class:
use \lithium\util\Set;
$users = Users::all(..conditions..);
$state_ids = array_flip(array_flip(Set::extract($users->data(), '/city/state_id')));
$stateList = States::find('list',array(
'conditions' => array(
'id' => $state_ids
),
));
You can set up relationships in this way, but you have to use a more verbose relationship definition. Have a look at the data that gets passed when constructing a Relationship for details about the options you can use.
class Users extends \lithium\data\Model {
public $belongsTo = array(
"Cities" => array(
"to" => "app\models\Cities",
"key" => "city_id",
),
"States" => array(
"from" => "app\models\Cities",
"to" => "app\models\States",
"key" => array(
"state_id" => "id", // field in "from" model => field in "to" model
),
),
);
}
class Cities extends \lithium\data\Model {
public $belongsTo = array(
"States" => array(
"to" => "app\models\States",
"key" => "state_id",
),
);
}
class States extends \lithium\data\Model {
protected $_meta = array(
'key' => 'id', // notice that this matches the value
// in the key in the Users.States relationship
);
}
When using the States relationship on Users, be sure to always include the Cities relationship in the same query. For example:
Users::all( array(
'with' => array(
'Cities',
'States'
)
) );
I have never tried this using belongsTo relationships, but I have it working using hasMany relationships in the same way.