How to convert object return by laravel model factory create method into array containing model fields? - laravel

For example, I have a UserFactory.php
<?php
use App\User;
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'role' => 'USER',
'password' => 'sasdcsdf34', // password
'remember_token' => Str::random(10),
];
});
Now, I can create a user as following
$user = factory(User::class)->create();
Now, How can I convert this $user object into array containing user info like name,email etc without initializing new array and manually assigning every $user object property. ??
I DON'T want to manually assign like following as it is tedious if there are many properties in $user object
$userArray=[
'id' => $user->id,
'name' => $user->name,
'email' => $user->email
]
I have tried this but it creates array containing various other properties and actual values needed are nested inside properties
$userArray=array($user)

You should try using the raw method of factory instead of create.
$user = factory(User::class)->raw();
This should give you an array you can work with.

Try to add something like this to your model class:
public function getArr(){
foreach($this->attributes as $key => $val){
$array[$key] = $val;
}
return $array;
}
If you wish to have this function in every model you could create trait with this function and then just attach it in model class or any class extending it.

You can use json_decode.
// Laravel 7
$userArray = json_decode(factory(User::class)->create(), true);
// Laravel 8
$userArray = json_decode(User::factory()->create(), true);

For Laravel 8, instead of make or create method, use:
User::factory()->raw();
This will return an array

Related

Laravel Validating An Array in Update Method unique filter

I am new to Laravel. I try to validate an array in Laravel 9.
for using a unique filter I have a problem.
at first, I try to use this way
$rules = [
'*.id' => 'integer|required',
'*.key' => 'string|unique.settings|max:255|required',
'*.value' => 'array|nullable|max:255',
];
For the Create method, this works, but for updating, the logic is wrong. I need to ignore the current field.
for the update, I try to use this way
private function update(): array
{
foreach ($this->request->all() as $keys => $values) {
// dd($values['id']);
$rules[$keys .'.id' ] = 'integer|required';
$rules[$keys .'.key'] = ['string|max:255|required', Rule::unique('settings', 'key')->ignore($values['id'])];
$rules[$keys .'.value'] = 'array|nullable|max:255';
}
// dd($rules);
return $rules;
}
I got this error
BadMethodCallException: Method Illuminate\Validation\Validator::validateString|max does not exist. in file /Users/mortezashabani/code/accounting/vendor/laravel/framework/src/Illuminate/Validation/Validator.php on line 1534
how can I validate an array in the update method in Laravel 9?
PS: without Rule::unique('settings','key')->ignore($values['id'])] all filter is works without any problem
hello you can try this code in your function
$validated = $request->validate([
'id' => 'required',
'key' => 'string|unique.settings|max:255|required',
'value' => 'array|nullable|max:255',
]);

laravel endpoint hide field

How can i hide some fields ?
i want to hide the file field
Eloquent :
$reports = Report::select('id', 'file','company_id', 'title', 'year', 'created_at')
->orderBy('id', 'desc')
->paginate(10);
return ReportResource::collection($reports);
Model :
...
public function getFileSizeAttribute()
{
return Storage::disk('files')->size($this->attributes['file']);
}
....
ReportResource:
...
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'year' => $this->year,
'views' => $this->whenNotNull($this->views),
'file' => $this->whenNotNull($this->file), <-- i want to hide the file field
'file_size' => $this->fileSize, <-- but always show file_size
'created_at' => $this->created_at,
'company' => new CompanyResource($this->company),
];
}
to get file_size field i must select the file field , because it's depends on it to calculate the file size.
but i want to hide the file field before send the response.
i know i can use the protected $hidden = [] method in the model , but i don't want that, because file field it's required on others place. i just want to hide it on this endpoint only.
Since you are using API resources the best and clean way to do this is by using a Resource class for your collection.
Said that, you will have 3 Resources:
The first one, as it is, just for retrieving a single Model with file and file_size attributes. The one you already have ReportResource.php
...
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'year' => $this->year,
'views' => $this->whenNotNull($this->views),
'file' => $this->whenNotNull($this->file),
'file_size' => $this->fileSize,
'created_at' => $this->created_at,
'company' => new CompanyResource($this->company),
];
}
A new second resource to be used in your endpoint, without the file attribute. IE: ReportIndexResource.php
...
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'year' => $this->year,
'views' => $this->whenNotNull($this->views),
'file_size' => $this->fileSize,
'created_at' => $this->created_at,
'company' => new CompanyResource($this->company),
];
}
Now you need to create a Resource collection which explicitly defines the Model Resource to use. IE: ReportCollection.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\ResourceCollection;
class ReportCollection extends ResourceCollection
{
/**
* The resource that this resource collects.
*
* #var string
*/
public $collects = ReportIndexResource::class;
}
Finally, use this new resource collection in your endpoint
$reports = Report::select('id', 'file','company_id', 'title', 'year', 'created_at')
->orderBy('id', 'desc')
->paginate(10);
return new ReportCollection($reports);
Of course, you can make use of makeHidden() method, but IMO is better to write a little more code and avoid a non desired attribute in your response because you forgot to make it hidden.
Also, in case you make use of makeHidden() method and you want to show the attribute in a future, you will have to update all your queries instead of a silgle resource file.
If you want to make it Hide From All Returns , you can Do this in model
protected $hidden = ['file'];
and if you want to do it temporirly with this query , you can Use MakeHidden method
$users = $reports->makeHidden(['file']);
It's clear in laravel docs , take a look
https://laravel.com/docs/9.x/eloquent-collections#method-makeHidden

Laravel 8 multiple models to single view Error $address Not defined

I'm trying to create 2 rows in the DB using findOrNew() but when I use the ID from the Users model to create another model(Address) the programs returns undefined variable $address. I don't know if I'm using the correct approach or not. Bellow you can view my approach. Can you lead me to the right approach or where to find it?
2 models one view:
seeing what you have in your method is returning an undefined because it is not executing the findOrNew method correctly, check this link, maybe it will help you and this same
the second is that if you are passing the values by post everything will come to you in the $req parameter and only there then if you want to use the id you would have to access through $req->id if you send the data correctly
the third I see that in the view method you are passing 3 parameters when you should only pass two the first the name of the view the second the arrangement with the data that you will pass to the view
public function detail(Request $req)
{
$user = User::firstOrNew($req->id);
$user->user_type_id = 1;
$user->name = $req->name;
$user->last_name = $req->last_name;
$user->email = $req->email;
$user->password = Hash::make(Str::random(8));
$user->save();
$address = UserAddress::firstOrCreate(['user_id' => $req->id]); //or maybe $user->id
return view('user.detail', [
'user' => $user,
'adderss' => $address
]);
}
finally you may prefer to use the updateOrCreate method
public function detailV2(Request $req)
{
$user = User::updateOrCreate(
['id' => $req->id],
[
'user_type_id' => 1,
'name' => $req->name,
'last_name' => $req->last_name,
'email' => $req->email,
'password' => Hash::make(Str::random(8)),
]
);
$address = UserAddress::firstOrCreate(['user_id' => $user->id]);
return view('user.detail', [
'user' => $user,
'adderss' => $address
]);
}

Symfony\Component\Debug\Exception\FatalThrowableError

i'm trying to seed data to database using laravel.
this is my factory model
$factory->define(App\product::class, function (Faker\Generator $faker) {
return [
'name' => $faker->name,
'description' => $faker->description,
'price' =>$faker->price,
'image' => $faker->image,
'value' => $faker->value,
'category_id' => $faker->category_id,
'is_voucher' => $faker->is_voucher,
'voucher_id' => $faker->voucher_id,
];
});
in the producttableseed
public function run()
{
$product = factory(product::class, 10)->create();}
and when i run php artisan db:seed
i get this error
Symfony\Component\Debug\Exception\FatalThrowableError : Argument 1 passed to Illuminate\Database\Eloquent\Factory::{closure}() must be an instance of Faker\Generator\Generator, instance of Faker\Generator given
Do you have the line
use Faker\Generator as Faker;
before you define your factory? This, plus changing first line to this
$factory->define(App\product::class, function (Faker $faker) {
works for me.
Also, be careful with
$product = factory(product::class, 10)->create();}
You are seeding 10 database entries here. Your variable name being singular, looks like you might be up for a surprise when you try working with an array that has multiple entries.

Using a php variable for validation in Laravel 4.2

I have this code that gets an object in a session and i put it in a certain variable. Then i wanted to use it in the laravel 4.2 'same' validation. So far here is the code i have
session_start();
$getsCapt = $_SESSION["captcha"];
$rules = array(
'st' => 'required',
'capt' => 'required|numeric|same:$getsCapt'
);
It is not doing anything. What i wanted to have is i'll compare the value i get from the session with the value i get from the textbox in my view named 'capt' but so far its not doing anything. any ideas to do this properly?
First of all, You are using same validator incorrectly.
same expects a form field name
Example:
same:field_name
Where, the given field must match the field under validation.
You could register and use a Custom Validation Rule
Validator::extend('captcha', function($attribute, $value, $parameters)
{
$captcha = \Session::get('captcha');
return $value == $captcha;
});
So later you can do:
//session_start(); - Please no need for this in Laravel
//$getsCapt = $_SESSION["captcha"]; - Also remove this not necessary
$rules = array(
'st' => 'required',
'capt' => 'required|numeric|captcha'
);
NB:
Use Session::put to save something to session e.g \Session::put('something');
There is also Session::get for retrieving value from session e.g \Session::get('something');
Please avoid using $_SESSION not Laravel way of doing things
[Edited] Where to Register Custom Validation Rule?
There are basically two ways you can register a custom validation rule in Laravel.
1. Resolving from a closure:
If you are resolving through closure you can add it to : app/start/global.php
Validator::extend('captcha', function($attribute, $value, $parameters)
{
$captcha = \Session::get('captcha');
return $value == $captcha;
});
2. Resolving from a class
This is the best and preferred way of extending custom validation rule as its more organised and easier to maintain.
i. Create your own validation class, CustomValidator.php, maybe in app/validation folder
<?php namespace App\Validation;
use Illuminate\Validation\Validator;
use Session;
class CustomValidator extends Validator{
public function validateCaptcha($attribute, $value, $parameters)
{
$captcha = Session::get('captcha');
return $value == $captcha;
}
}
NB: Notice the prefix validate used in the method name, validateCaptcha
ii. Create a Service Provider that will resolve custom validator extension in app/validation folder
<?php namespace App\Validation;
use Illuminate\Support\ServiceProvider;
class CustomValidationServiceProvider extends ServiceProvider {
public function register(){}
public function boot()
{
$this->app->validator->resolver(function($translator, $data, $rules, $messages){
return new CustomValidator($translator, $data, $rules, $messages);
});
}
}
iii. Then add CustomValidationServiceProvider under app/config/app.php providers array:
'providers' => array(
<!-- ... -->
'App\Validation\CustomValidationServiceProvider'
),
iv. And add the custom error message in app/lang/en/validation.php
return array(
...
"captcha" => "Invalid :attribute entered.",
...
)
Change single quotes to double quotes
$rules = array(
'st' => 'required',
'capt' => "required|numeric|same:$getsCapt"
);
Or simply concatenate the value
$rules = array(
'st' => 'required',
'capt' => 'required|numeric|same:' . $getsCapt
);

Resources