Laravel seeder not working - php

Can anyone see what seems to be the problem with my seeder?
public function run()
{
$faker = Faker\Factory::create();
$limit = 30;
$userId = App\User::all()->lists('id')->toArray();
$status = App\OrderStatus::all()->lists('id')->toArray();
for ($i = 0; $i < $limit; $i++) {
$chosenUserId = $faker->randomElement($userId);
$user = App\User::find($chosenUserId);
DB::table('orders')->insert([
'created_at' => $faker->date('Y-m-d'),
'user_id' => $chosenUserId,
'status_id' => $faker->randomElement($status),
'draft' => false,
'address_id' => $user->addresses->first()->id
]);
}
}
I keep getting trying to get property of non-object error, and I suppose it's because of the last line where I'm attaching address_id.
When I take a look at the DB what was created until that point, users and addresses are created fine, and each user has an address assigned to him.
In user model i have:
public function addresses()
{
return $this->hasMany('App\Address');
}

Here:
addresses -> addresses()

Since your User model have a function to define the relationship with address model, you should call it as a function not as object attributes:
DB::table('orders')->insert([
'created_at' => $faker->date('Y-m-d'),
'user_id' => $chosenUserId,
'status_id' => $faker->randomElement($status),
'draft' => false,
'address_id' => $user->addresses()->first()->id
]);

Related

Problem saving data into Polymorphic relationship laravel

I have some doubts on polymorphic relationship.
I have the schema attached where document can be connected to sectors if 'senderable_type' is Sector or, to addresses if is Address.
Base on value get from a form, I know if it is connected to a Sector or to an Address, getting its ID.
But...how to do this? Can you help me please?
Each document can be linked to one sector or to one address. Is it possible to use Polymorphic for this use?
These are my relationships on models:
//Document.php
public function documentable()
{
return $this->morphTo();
}
//Sector.php
public function documents()
{
return $this->morphMany(Document::class, 'senderable');
}
//Address.php
public function documents()
{
return $this->morphMany(Document::class, 'senderable');
}
And this is the code of my store function in my controller:
if (is_null($request->get('sender_id'))) {
$type = "App\Sector";
$sender_id = $request->get("sector_id");
} else {
$type = "App\Address";
$sender_id = $request->get("sender_id");
}
$documento = Document::create(
[
'company_id' => $request->get("company_id") ?? Auth::user()->company_id,
'date' => Carbon::createFromFormat("d/m/Y", $request->get("date")),
'type' => $request->get("origin"),
'subject' => $request->get("subject"),
'senderable_type' => $type,
'senderable_id' => $sender_id,
'protocol_number' => '0',
'protocol_date' => Carbon::now(),
'is_reserved' => false,
'created_user_id' => Auth::id(),
]
);
Actually I check if it is related to a Sector or to an Address and manually save in the DB. I don't know if it is the best way...

Laravel Factory: Manual Increment of Column

For the following factory definition, the column order needs to be sequential. There is already a column id that is auto-incremented. The first row's order should start at 1 and each additional row's order should be the next number (1,2,3, etc.)
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => (App\AliasCommand::count()) ?
App\AliasCommand::orderBy('order', 'desc')->first()->order + 1 : 1
];
});
It should be setting the order column to be 1 more than the previous row, however, it results in all rows being assigned 1.
Here's something that might work.
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
static $order = 1;
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => $order++
];
});
It just keeps a counter internal to that function.
Update:
Laravel 8 introduced new factory classes so this request becomes:
class AliasCommandFactory extends Factory {
private static $order = 1;
protected $model = AliasCommand::class;
public function definition() {
$faker = $this->faker;
return [
'user_id' => User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => self::$order++
];
}
}
The answer by #apokryfos is a good solution if you're sure the factory model generations will only be run in sequential order and you're not concerned with pre-existing data.
However, this can result in incorrect order values if, for example, you want to generate models to be inserted into your test database, where some records already exist.
Using a closure for the column value, we can better automate the sequential order.
$factory->define(App\AliasCommand::class, function (Faker\Generator $faker) {
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => function() {
$max = App\AliasCommand::max('order'); // returns 0 if no records exist.
return $max+1;
}
];
});
You almost had it right in your example, the problem is that you were running the order value execution at the time of defining the factory rather than the above code, which executes at the time the individual model is generated.
By the same principle, you should also enclose the user_id code in a closure, otherwise all of your factory generated models will have the same user ID.
To achieve true autoIncrement rather use this approach:
$__count = App\AliasCommand::count();
$__lastid = $__count ? App\AliasCommand::orderBy('order', 'desc')->first()->id : 0 ;
$factory->define(App\AliasCommand::class,
function(Faker\Generator $faker) use($__lastid){
return [
'user_id' => App\User::inRandomOrder()->first()->id,
'command' => $faker->word,
'content' => $faker->sentence,
'order' => $faker->unique()->numberBetween($min=$__lastid+1, $max=$__lastid+25),
/* +25 (for example here) is the number of records you want to insert
per run.
You can set this value in a config file and get it from there
for both Seeder and Factory ( i.e here ).
*/
];
});
In Laravel 9 (and possibly some earlier versions?), there's a pretty clean way to make this happen when you're creating models (from the docs):
$users = User::factory()
->count(10)
->sequence(fn ($sequence) => ['order' => $sequence->index])
->create();
If you'd like to start with 1 instead of 0:
$users = User::factory()
->count(10)
->sequence(fn ($sequence) => ['order' => $sequence->index + 1])
->create();
The solution also solves already data on table conditions:
class UserFactory extends Factory
{
/**
* #var string
*/
protected $model = User::class;
/**
* #var int
*/
protected static int $id = 0;
/**
* #return array
*/
public function definition()
{
if ( self::$id == 0 ) {
self::$id = User::query()->max("id") ?? 0;
// Initialize the id from database if exists.
// If conditions is necessary otherwise it would return same max id.
}
self::$id++;
return [
"id" => self::$id,
"email" => $this->faker->email,
];
}
}

Using Fractal's $defaultIncludes

I am trying to use a $defaultIncludes() and am getting an exception --
ErrorException in ViewoptionTransformer.php line 8:
Argument 1 passed to App\Transformers\ViewoptionTransformer::transform() must be an instance of App\Viewoption, boolean given
Following the tutorial (http://laravelista.com/build-an-api-with-lumen-and-fractal/) except I am using Laravel 5.1 not Lumen:
in User model, I have the hasOne relationship with Viewoption called viewoptions
In the UsersController, I eager load viewoptions
public function index(Manager $fractal, UserTransformer $userTransformer)
{
$records = User::with(['locations', 'viewoptions'])->get();
$collection = new Collection($records, $userTransformer);
$data = $fractal->createData($collection)->toArray();
return $this->respondWithCORS($data);
}
In the UserTransformer, I have the $defaultInclude and the includes method
protected $defaultIncludes = ['viewoptions'];
`public function transform(User $user)
{
return [
'id' => $user->id,
'name' => $user->name,
'is_active' => (boolean)$user->is_active,
'is_admin' => (boolean)$user->is_admin,
'is_manager' => (boolean)$user->is_manager,
'role_id' => (integer) $user->role_id,
'email' => $user->email,
'phone' => $user->phone,
'full_sidebar' => (boolean)$user->full_sidebar
];
}
public function includeViewoptions(User $user)
{
$viewoptions = $user->viewoptions;
return $this->collection($viewoptions, new ViewoptionTransformer);
}`
Have a ViewoptionTransformer
`
use App\Viewoption;
use League\Fractal\Resource\Collection;
use League\Fractal\TransformerAbstract;
class ViewoptionTransformer extends TransformerAbstract {
public function transform(Viewoption $item)
{
//return $item;
return [
'id' => $item->id,
'user_id' => $item->user_id,
'voAgency' => (boolean)$item->voAgency,
'voBalanceDue' => (boolean)$item->voBalanceDue,
'voCloseDate' => (boolean)$item->voCloseDate,
'voCommitTotal' => (boolean)$item->voCommitTotal,
'voDistributor' => (boolean)$item->voDistributor,
'voDueDate' => (boolean)$item->voDueDate,
'voFeePercentage' => (boolean)$item->voFeePercentage,
'voRegion' => (boolean)$item->voRegion,
'voSeason' => (boolean)$item->voSeason,
];
}
}`
Worked with these and slight variations of these throughout the day yesterday and I can't rid myself of that exception.
Not all of your users.id corresponds to some viewoptions.user_id.
Just check it:
$records = User::with(['locations', 'viewoptions'])->get();
dd($records);
some viewoptions will be null or false or just undefined
Instead of using collection use item like so
public function includeViewoptions(User $user){
$viewoptions = $user->viewoptions;
return $this->item($viewoptions, new ViewoptionTransformer);
}`
I had a similar issue today, all my other uses of transformers had been with hasMany relationships. I was always instantiating the transformer with a collection of objects.
However, when using a transformer with a belongsTo relationship and instantiating the transformer with only one object (similar to how you are passing only one object from a hasOne relationship) I would get the same boolean given error.
In the end I solved the issue by using 'item' instead of 'collection' when instantiating the transformer.
Within your includeViewoptions function
Instead of using
return $this->collection($viewoptions, new ViewoptionTransformer);
try
return $this->item($viewoptions, new ViewoptionTransformer);

Call to undefined method Illuminate\Database\Query\Builder::associate()

Reference: How can I update an existing Eloquent relationship in Laravel 4?
$userinfo = \Userinfo::find($id);
\User::find($id)->userinfo()->associate($userinfo)->save();
I'm getting the error: Call to undefined method Illuminate\Database\Query\Builder::associate()
Here is the entire method:
public function saveUser($id)
{
$user = \User::find($id);
$userdata = \Input::all();
$rules = array(
'email' => 'required|email',
'state' => 'size:2',
'zip' => 'size:5',
'phone' => array('regex:/^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/')
);
$validator = \Validator::make($userdata, $rules);
if ($validator->passes())
{
if ($userdata['email'] !== $user->email)
{
$rules = array('email' => 'unique:users');
$validator = \Validator::make($userdata, $rules);
if ($validator->fails()) return Redirect::route('admin.user.edit', array('user' => $user))
->with('error', 'Specified email already exists.');
}
$user->email = $userdata['email'];
$user->firstname = $userdata['firstname'];
$user->lastname = $userdata['lastname'];
$userinfoArray = array(
'address' => $userdata['address'],
'city' => $userdata['city'],
'state' => $userdata['state'],
'zip' => $userdata['zip'],
'phone' => preg_replace('/[^0-9]/', '', $userdata['phone'])
);
$user->save();
if (!$user->userinfo)
{
$userinfo = new \Userinfo($userinfoArray);
$userinfo = $user->userinfo()->save($userinfo);
}
else
{
$userinfo = \Userinfo::find($id);
\User::find($id)->userinfo()->associate($userinfo)->save();
//$user->userinfo()->update($userinfoArray);
}
return \Redirect::route('admin.user.detail', array('id' => $id))
->with('success', 'User updated.');
}
return \Redirect::route('admin.user.edit', array('id' => $id))
->withInput()
->withErrors($validator);
}
associate() is a method of the belongsTo relationship, but it looks like from the above you are trying to call it via the hasOne relationship.
I am just guessing as you have not provided your eloquent model class code so can't see how you have set the relationships exactly, but if you have:
class User extends Eloquent {
public function userinfo()
{
return $this->hasOne('Userinfo');
}
}
class Userinfo extends Eloquent {
public function user() {
return $this->belongsTo('User');
}
}
Then associate needs to be called against Userinfo as this has the belongsTo relationship to which the associate() method is attached.
For example
$user = \User::find(4);
$userinfo = \UserInfo::find(1);
$userinfo->user()->associate($user);
$userinfo->save();
Will set the foreign key user_id in the user_info table to the id of the $user object.
Looking at your above code it doesn't appear that this is what you are actually trying to do and that the
$user->userinfo()->update($userinfoArray);
call which you have commented out will in fact do what you seem to be trying to achieve, which is to update the userinfo that is related to the current user if that user already exists.
Hope this helps.
Glen
Change hasOne to belongsTo. It will look like:
class User extends Eloquent {
public function userinfo()
{
return $this->belongsTo('Userinfo');
}
}
class Userinfo extends Eloquent {
public function user() {
return $this->belongsTo('User');
}
}
I was stuck on this problem for a few days and it ended up being quite simple to solve. I had created a folder called 'models' in my 'app' folder but I had forgotten to reconfigure my auth.php file.
This was my error.
Call to undefined method Illuminate\Database\Query\Builder
I fixed it by opening the auth.php in the config folder and changing the following line to include my models folder.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Foodie\User::class,
fix:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => Foodie\Models\User::class,
Hope this helps!
You need to specify the field related like this:
public function profile()
{
return $this->hasOne('App\AdmProfile', 'id');
}

laravel 4 many to many relationship integration test not passing

Every entity is being saved and has an ai id. Only the test on line 34 is not passing.
<?php
class AssignmentTest extends TestCase
{
protected $assignment;
public function setUp()
{
parent::setUp();
$this->assignment = new Assignment;
}
public function testAssignmentAssociations()
{
$facility = Facility::create(array(
'name' => 'test facility',
'code' => 'test-facility'
));
$user = new User;
$user->id = 1;
$shift = Shift::create(array(
'name' => 'test shift',
'start_time' => 0,
'end_time' => 600
));
$this->assignment->facilities()->save($facility);
$this->assignment->shift()->associate($shift);
$this->assignment->user()->associate($user);
$this->assignment->save();
$this->assertEquals(1, $facility->id);
$this->assertEquals(1, $this->assignment->facilities()->count());
$this->assertEquals(1, $this->assignment->shift_id);
$this->assertEquals(1, $this->assignment->user_id);
}
}
// Facility model
public function assignments()
{
return $this->belongsToMany('Assignment', 'assignment_facilities');
}
// Assignment model
public function facilities()
{
return $this->belongsToMany('Facility', 'assignment_facilities');
}
Edit
Apparently removing this line will make the test successful. Now I'm interested as to why when saving the assignment the association will no longer return a successful count?
<?php
$this->assignment->save();
I havent tested - but dont you need to 'save' the shift and user records themselves, before you try and associate them against the assignment?
$user = new User;
$user->id = 1;
$shift = Shift::create(array(
'name' => 'test shift',
'start_time' => 0,
'end_time' => 600
));
$shift->id = 1;
$this->assignment->facilities()->save($facility);
$this->assignment->shift()->save($shift);
$this->assignment->user()->save($user);
$this->assignment->shift()->associate($shift);
$this->assignment->user()->associate($user);
$this->assignment->save();

Categories