Seed Multiple Specific Data on Laravel - php

I want to seed a database table by using local, s3 and rackspace using database seeder on Laravel. However, if I use this three specific name with the $faker->randomElement() method it just populate the same name multiple time and that's what I don't need. If possible, I also want to set the different value for the different column using s3 or rackspace storage name.
$factory->define(App\Storage::class, function (\Faker\Generator $faker) {
return [
'storage' => $faker->randomElement(['s3', 'local', 'rackspace']),
's3-key' => null,
's3-secret' => null,
's3-region' => null,
's3-bucket' => null,
'rackspace-username' => null,
'rackspace-key' => null,
'rackspace-container' => null,
'status' => 'active'
];
})
What would be the best way to achieve this?

There is a bug in the Faker/Provider/Baser.class, it is using this line of code inside the randomElement Function which is duplicating the same random element over and over for the same instance due to the fact it is using static:: keyword
static::randomElements($array, 1);
I'll report about it, for the moment use this piece of code:
$faker->randomElements(['s3', 'local', 'rackspace'],1)[0]

Related

Laravel set incremental id value when seeding table

I'm trying to seed a MySql table using Laravel seeder class. The problem is that it is not assigning the id field (which is an incremental) value as I set. In the seeder class I got:
public function run()
{
Patropi\Entidade::create([
'id' => '0',
'nome' => 'entidade 0',
'cpfcnpj' => '12345678901'
]);
Patropi\Fornecedor::create([
'id' => '0',
'prioridade' => '0'
]);
}
On the database, the Fornecedor table id is a foreign key which references the Entidade id, that's why I want to have the same Id on both. The problem is, when it inserts on Entidade it doesn't put it as id = 0 but instead it gives the value of the last incremental + 1. How to force laravel to insert 0 there instead? Thanks in advance.
The reason why it happens is Guarding Attributes. The attributes listed in $guarded array are protected from changes, what means Laravel will ignore all your attempts to modify them. Sometimes this approach is also known as Mass Assignment Protection.
By defualt, Laravel protects "id", so you can't and don't need to set them manually, however there's a way how to stop this default behavior. They key is in unguard() method.
Here's how you can fix your code:
public function run()
{
Patropi\Entidade::unguard();
Patropi\Entidade::create([
'id' => '0',
'nome' => 'entidade 0',
'cpfcnpj' => '12345678901'
]);
Patropi\Fornecedor::create([
'id' => '0',
'prioridade' => '0'
]);
}
Storing NULL or 0 in the auto-incrementing field is one of the triggers to assign the next incremental value.
From the MySQL docs:
You can also explicitly assign 0 to the column to generate sequence numbers.
If you want to disable this functionality, you can turn on the NO_AUTO_VALUE_ON_ZERO sql mode. This will change MySQL so that only assigning NULL will assign the next incremental value, and will allow you to store 0 in the field. From the docs:
NO_AUTO_VALUE_ON_ZERO affects handling of AUTO_INCREMENT columns. Normally, you generate the next sequence number for the column by inserting either NULL or 0 into it. NO_AUTO_VALUE_ON_ZERO suppresses this behavior for 0 so that only NULL generates the next sequence number.
This mode can be useful if 0 has been stored in a table's AUTO_INCREMENT column. (Storing 0 is not a recommended practice, by the way.)
If you don't explicitly need the id to be 0, then I would not try to assign 0. If the id doesn't matter, then you can do this:
public function run()
{
$entidade = Patropi\Entidade::create([
'nome' => 'entidade 0',
'cpfcnpj' => '12345678901'
]);
Patropi\Fornecedor::create([
'id' => $entidade->id,
'prioridade' => '0'
]);
}
Or, if you have the Eloquent relationships setup:
public function run()
{
$entidade = Patropi\Entidade::create([
'nome' => 'entidade 0',
'cpfcnpj' => '12345678901'
]);
// assumes fornecedor() defines a hasone/hasmany relationship.
$entidade->fornecedor()->create([
'prioridade' => '0'
]);
}

Adding a conditional value to extra column in pivot table from array in Laravel

I know the Question title is a bit murky, but here's what I'm trying to do:
I'm retrieving a list of groups that a user belongs to from a third party api. In some cases, the user will be an 'admin' for a group and other times, just a 'member'.
Specifics aside, I'm calling a method on my api class from my controller that hits the api, retrieves the user's groups, decides if they are an 'admin' or not, then returns an array of arrays with each group's information including a 'role' key that denotes whether or not they are an 'admin'. So my returned array looks something like this:
[
0 => [
'unique_id' => 1243657,
'name' => 'Group1',
'city' => 'Bluesville',
'state' => 'IN',
'role' => 'admin'
],
1 => [
'unique_id' => 4324567,
'name' => 'Group2',
'city' => 'New Curtsbourough',
'state' => 'WI',
'role' => 'member'
],
2=> [
'unique_id' => 87463652,
'name' => 'Group3',
'city' => 'Samsonite',
'state' => 'MN',
'role' => 'member'
]
]
Now, I need to take those groups and store them in the database, which I'm doing by checking first that the group doesn't exist in the database, then adding it if needed. Of course, I'm leaving off the role, as it is only relevant to the current user.
Next, I need to connect the current user to these groups that were just retrieved. I have a pivot table set up that currently holds the user_id and group_id.
The question is, how to best handle this. Before I decided that I needed to know whether or not a member was an 'admin' or not, I simply had my 'createGroups' method return an array of primary keys to me, then passed that array to a call to
$user->groups()->sync($array_of_ids);
However, with the added 'role' information, it's not as cut and dry.
Basically, at this point in the lifecycle, I have access to an array of groups that contains a field 'role'. My thinking says to add a 'role' field to the pivot table, which would then contain 'user_id', 'group_id' and 'role'. This means I'll not only need the $groups array with the retrieved groups, but the ids of those groups as they pertain to my database.
I could make something work, but I'm afraid it would be extremely messy and inefficient.
Thoughts anyone??
Ok, as happens many times on Stackoverflow, I've come to a solution for my own question. I'm posting so that in the off-chance someone stumbles upon my question needing to do something similar, they can at least see how one person handled it.
According to the Laravel docs, if you want to sync relationships with an added column, you need to call sync in the following way:
$user->groups()->sync([
1 => ['role' => 'admin'],
2 => ['role' => 'member'],
3 => ['role' => 'member']
]);
So before I could sync, I needed an array that resembled the array that is being passed to 'sync'.
Since I had an array of 'groups' that included a field called 'role' for each group, I created a 'createGroups' method that basically looped over the $groups array and called the 'insertGetId' method that Laravel provides. This method persists the object to the database and returns the primary key of the created record. For my 'createGroups' method, I did the following:
public function createGroups($groups)
{
$added = array();
foreach($groups as $group){
$id = $this->createGroup($group);
$added[$id] = ['role' => $group['role']];
}
return $added;
}
So as I'm inserting 'groups' into the database, I'm building up the array that is needed by the 'sync' method. Since the 'createGroup' method uses Laravel's 'insertGetId' method, it returns the primary key for that group. Then I use that id as the key to the array. After all groups are inserted, my 'added' array that is returned to my controller, looks like this:
[
1 => ['role' => 'admin'],
2 => ['role' => 'member'],
3 => ['role' => 'member']
]
which is exactly what the 'sync' method needs to do it's thing.
Happy coding!

in Laravel Model Factories when I do a make() and set a timestamp field, the function is trying to hit the database

This is hitting the database
$organization = factory(ilos\Models\Organization::class)->make([
"created_at" => Carbon::now()->subWeek(3),
"is_paid" => true,
"paid_until" => Carbon::now()->addWeek(1),
]);
This is not
$organization = factory(ilos\Models\Organization::class)->make([
"is_paid" => true,
"paid_until" => Carbon::now()->addWeek(1),
]);
Isn't make supposed to never hit the database?
how can I achieve the expected outcome?
I need to set the created_at to check if the organization is still in trial (this is for a unit test) and I don't want to touch the database.
Thanks for your help

Algolia keeps casting tmy data to a string

I have been succesful in uploading my data to algolia using laravel. My create method looks like this:
Beer::firstOrCreate([
'name' => $beer['title'],
'description' => $beer['description'],
'path' => '/uploads/gall/' . $filename,
'brewery_id' => '',
'abv' => $abv
]);
It gathers data from an api and works perfectly, except for the abv value. It needs to be a numeric type in algolia but whenever I check it in algolia it is a string.
Even when I force it to a float or int by using:
(float)$abv
I still end up with a string in my Algolia database. Funny enough the primary id for this record that is being auto incremented is not a string and looks fine in the algolia database.
To implement algolia in laravel I used the laravel helper in my model:
// Send new records to the algolia database
use AlgoliaEloquentTrait;
I hope somebody can maybe give me slight hint of what I could be doing wrong.
I am assuming that the data type of 'abv' inside your database is float and not string, if this is the case then try using floatval($abv). Your code would be something like:
Beer::firstOrCreate([
'name' => $beer['title'],
'description' => $beer['description'],
'path' => '/uploads/gall/' . $filename,
'brewery_id' => '',
'abv' => floatval($abv)
]);
Cheers,,

How do I Implement AUTO_INCREMENT in a Yii2 Migration Using MySQL?

I have created a yii2 (v2.0.6) migration for a simple MySQL (v5.6.21) table. Everything works, except that I cannot figure out how to AUTO_INCREMENT the primary key. The problem seems to be that I am using a small integer rather than the more standard long integer datatype. Here is my migration code:
$this->createTable('{{%status}}', [
'id' => $this->smallInteger(8)->unique(),
//'id' => $this->primaryKey(11),
'description' => $this->string(20),
]);
$this->addPrimaryKey('','status','id');
I could get around the problem by using the ->primaryKey() method, which is commented out in line 3 above, but then yii creates a long integer datatype, and I am trying to avoid that. Any insight into the problem will be much appreciated.
If it is critical to have that column type, you can always change it:
$this->createTable('{{%status}}', [
'id' => $this->primaryKey(11),
'description' => $this->string(20),
]);
$this->alterColumn('{{%status}}', 'id', $this->smallInteger(8).' NOT NULL AUTO_INCREMENT');
(I've tested this with MySQL - it works)
However, like #scaisEdge says, it's usually not worth the troble.
Why not a simply primaryKey?, the format for integer(8) , integer(11) or primary key is always the same is always an integer long
then or you need a small int (max 5 digit) or you can use the normal $this->primaryKey() because
SMALLINT is for storage of 2 byte (value -32768 32767) an then
smallInteger(8) is not coherent. the numer 8 is for output not for store format. If you want 8 digit you need at least
INT of 4 byte -2147483648 2147483647 or more
$this->createTable('posts', [
'post_id' => "bigint(20) unsigned NOT NULL AUTO_INCREMENT",
'loc_id' => $this->integer(10)->unsigned()->notNull(),
"PRIMARY KEY (`post_id`,`loc_id`)",
], 'ENGINE=InnoDB DEFAULT CHARSET=utf8');
This works for me
$this->createTable('new_table',[
'id' => Schema::TYPE_PK.' NOT NULL AUTO_INCREMENT',
'name' => Schema::TYPE_STRING,
'age' => Schema::TYPE_INTEGER
]);
However you can simply use the below style and Yii will replace the 'pk' type of id based on your DBMS. for MYSQL it will be int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY
$this->createTable('new_table',[
'id' => 'pk',
'name' => Schema::TYPE_STRING,
'age' => Schema::TYPE_INTEGER
]);
Another (imo more readable) approach is:
$this
->integer()
->unsigned()
->notNull()
->append('AUTO_INCREMENT');

Categories