Laravel - How to Dynamically implement my API - laravel

I am consuming an external API using Guzzle and saving it into database:
use App\Employee;
public function handle()
{
$client = new GuzzleHttp\Client();
$res = $client->request('GET','https://api.employees.net/allemployees');
$clientdatas = json_decode($res->getBody()->getContents(), true);
foreach($clientdatas as $clientdata)
{
$employee = HrEmployee::updateOrCreate([
'employee_code' => $clientdata['staff_id'],
],
[
'first_name' => $clientdata['first_name'],
'last_name' => $clientdata['last_name'],
'other_name' => $clientdata['middle_name'],
'dept_code' => $clientdata['department_id']
]);
}
}
Currently what I have is that if
'employee_code' => $clientdata['staff_id'],
exists, it should update
[
'first_name' => $clientdata['first_name'],
'last_name' => $clientdata['last_name'],
'other_name' => $clientdata['middle_name'],
'dept_code' => $clientdata['department_id']
]);
it should save new records.
However, I want to change it that if
'employee_code' => $clientdata['staff_id'],
exists, it should update
[
'first_name' => $clientdata['first_name'],
'last_name' => $clientdata['last_name'],
'other_name' => $clientdata['middle_name'],
]);
except
[
'dept_code' => $clientdata['department_id']
]);
If not, it should save everything
How do I achieve this?
Thanks

Create payloads based on $clientdata['staff_id']
$payloads = [
'first_name' => $clientdata['first_name'],
'last_name' => $clientdata['last_name'],
'other_name' => $clientdata['middle_name']
];
if(!isset($clientdata['staff_id']) { // only add dept_code if staff_id is not set
$payloads['dept_code'] = $clientdata['department_id'];
}
$employee = HrEmployee::updateOrCreate([
'employee_code' => $clientdata['staff_id'],
], $payloads);

Related

Laravel Livewire Mixed Content error in production

I deployed a Laravel-Livewire on Digital Ocean and now I'm having a Mixed content problem when I try to upload a file.
Here is the error:
UploadManager.js:131 Mixed Content: The page at 'https://intake.freejiji.ca/clients/3/extensions' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://intake.freejiji.ca/livewire/upload-file?expires=1625251608&signature=9d98c598db4f6fccc01c009bcfc3051c6a97b56f4058f4d9489a8d30d6d497c2'. This request has been blocked; the content must be served over HTTPS.
The error happens when after I click "Select File" and chose the .csv file I want. Since I'mdoing this on a livewire component I'm not sure how to fix this so that the request goes over HTTPS instead of HTTP.
I was able to fix similar problems on the app by changing "asset()" with "secure_asset()"
and "route()" with "secure_url()" but in this case I'm not sure what to do.
Here is the whole "Import" component:
<?php
namespace App\Http\Livewire\Modals;
use Validator;
use Livewire\Component;
use App\Http\Traits\Csv;
use App\Models\AccountUser;
use Livewire\WithFileUploads;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
class ImportExtensions extends Component
{
use WithFileUploads;
public $clientID;
public $showModal = false;
public $upload;
public $columns;
public $fieldColumnMap = [
'first_name' => '',
'last_name' => '',
'email' => '',
'password' => '',
'extension' => '',
'user_type' => '',
];
protected $rules = [
'fieldColumnMap.first_name' => 'required|max:255',
'fieldColumnMap.last_name' => 'required|max:255',
'fieldColumnMap.email' => 'required|max:255',
'fieldColumnMap.password' => 'required|max:255',
'fieldColumnMap.extension' => 'required|max:255',
'fieldColumnMap.user_type' => 'required|max:255',
];
protected $validationAttributes = [
'fieldColumnMap.first_name' => 'First Name',
'fieldColumnMap.last_name' => 'Last Name',
'fieldColumnMap.email' => 'Email',
'fieldColumnMap.password' => 'Password',
'fieldColumnMap.extension' => 'Extension',
'fieldColumnMap.user_type' => 'User Type',
];
public function updatingUpload($value)
{
Validator::make(
['upload' => $value],
['upload' => 'required|mimes:csv'],
)->validate();
}
public function updatedUpload()
{
$this->columns = Csv::from($this->upload)->columns();
$this->guessWhichColumnsMapToWhichFields();
}
public function import()
{
// Validate that you are importing any data
$this->validate();
$importCount = 0;
Csv::from($this->upload)
->eachRow( function ($row) use (&$importCount){
$eachRow = $this->extractFieldsFromRow($row);
// Validate each Row of the csv file
$validatedData = Validator::make([
'first_name' => $eachRow['first_name'],
'last_name' => $eachRow['last_name'],
'email' => $eachRow['email'],
'password' => $eachRow['password'],
'extension' => $eachRow['extension'],
'user_type' => $eachRow['user_type'],
],[
'first_name' => 'required',
'last_name' => 'required',
'password' => 'required|max:255',
'user_type' => 'required|in:user,admin',
'email' => 'required|email|unique:account_users',
'extension' => ['required', 'numeric', Rule::unique('account_users', 'extension')
->where(function($query)
{return $query->where("account_id", $this->clientID);
})],
],);
if($validatedData->fails()){
$this->notify(['error','Oops something went wrong!']);
}else{
AccountUser::create([
'user_id' => Auth::user()->id,
'account_id' => $this->clientID,
'first_name' => $eachRow['first_name'],
'last_name' => $eachRow['last_name'],
'email' => $eachRow['email'],
'password' => $eachRow['password'],
'extension' => $eachRow['extension'],
'user_type' => $eachRow['user_type'],
]);
$importCount++;
}
});
$this->reset();
$this->emit('refreshExtensions');
if($importCount!=0) $this->notify(['success','Successfully Imported '.$importCount.' Extensions']);
}
public function guessWhichColumnsMapToWhichFields()
{
$guesses = [
'first_name' => ['first_name', 'name'],
'last_name' => ['last_name'],
'email' => ['email'],
'password' => ['password', 'pass'],
'extension' => ['extension', 'ext'],
'user_type' => ['user_type', 'user', 'type'],
];
foreach ($this->columns as $column) {
$match = collect($guesses)->search(fn($options) => in_array(strtolower($column), $options));
if ($match) $this->fieldColumnMap[$match] = $column;
}
}
public function extractFieldsFromRow($row)
{
$attributes = collect($this->fieldColumnMap)
->filter()
->mapWithKeys(function($heading, $field) use ($row) {
return [$field => $row[$heading]];
})
->toArray();
return $attributes;
}
public function downloadTemplate()
{
$filename = 'extensions_template.xls';
$path = public_path('files/' . $filename);
return response()->download($path, $filename, [
'Content-Type' => 'application/vnd.ms-excel',
'Content-Disposition' => 'inline; filename="' . $filename . '"'
]);
}
}
If you get mixed content problem it is mostly about you fetching the assets or resources from different http scheme. Here you are using HTTP to fetch data in HTTPS site. Change all the links to have HTTPS link.
If you want to force all the routes to use https you can achieve this by using following code.
if(env('APP_ENV', 'production') == 'production') { // use https only if env is production
\URL::forceScheme('https')
}
The above should solve your problem as all contents now will load from https.

Laravel Phpunit testing a request that take give output based on the request

I'm still new to laravel and I have a simple app and aSo I have a route that will store data based on the request in my controller.
public funtion store(Request $request, $id){
if ($request->has('work_experiences')) {
WorkExperience::create([
'user_id' => $user->id,
'position' => $request->work_experiences['position'],
'company' => $request->work_experiences['company'],
'start_date' => $request->work_experiences['start_date'],
'end_date' => $request->work_experiences['end_date'],
]);
}
if ($request->has('education')) {
Education::create([
'user_id' => $user->id,
'degree' => $request->education['degree'],
'university' => $request->education['university'],
'start_date' => $request->education['start_date'],
'end_date' => $request->education['end_date'],
]);
}
if ($request->has('job_interests')) {
JobInterest::create([
'user_id' => $user->id,
'job_position' => $request->job_interests['position'],
]);
}}
}
and in my test
public function test_authenticated_user_can_edit_education_profile()
{
$this->withoutExceptionHandling();
$user = User::factory()->create();
$this->actingAs($user);
$response = $this->post('/candidate' . '/' . $user->id, [
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
]);
$this->assertCount(1, WorkExperience::all());
}
when I run the test, the assertCount seems to fail because the response didn't work/insert the data to DB. where do I do wrong?
Well, the test is right.
It should fail because there is no work_experiences key in your request data.
The test request should look like:
$response = $this->post('/candidate' . '/' . $user->id, [
'work_experiences' => [
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
]
]);
So your data should go under a work_experiences key such that $request->has('work_experiences') returns true and executes the WorkExperience::create() statement.
Currently your endpoint only allows for a single "work experience" to be created. Seeing that you've named it work_experiences I assume you'd want to pass in an array/collection of "work experiences" - but that won't work with the current implementation; you'll have to loop over them instead - something like this:
if ($request->has('work_experiences')) {
foreach ($request->input('work_experiences') as $experience) {
WorkExperience::create([
'user_id' => $request->user()->id,
'position' => $experience['position'],
'company' => $experience['company'],
'start_date' => $experience['start_date'],
'end_date' => $experience['end_date'],
]);
}
}
And then your test should look something like this:
$response = $this->post('/candidate' . '/' . $user->id, [
'work_experiences' => [
[
'user_id' => $user->id,
'position' => 'position',
'company' => 'company',
'start_date' => Carbon::now(),
'end_date' => Carbon::now(),
],
// more "work experiences"
]
]);

mutiple emails controller is not working how do i solve?

i have a problem this controller is not working how can i do? should send mutiple emails how do i solve?
I don't know how to handle it
function submit(Request $request) {
$this->validate($request, [
'email' => 'required|email',
'file' => 'mimes:pdf,doc,docx'
]);
$data = array(
'name' => $request->name,
'cognome' => $request->cognome,
'luogo' => $request->luogo,
'date' => $request->date,
'telefono' => $request->telefono,
'email' => $request->email,
'citta' => $request->citta,
'provincia' => $request->provincia,
'studio' => $request->studio,
'lingua' => $request->lingua,
'livello' => $request->livello,
'lingua2' => $request->lingua2,
'livello2' => $request->livello2,
'file' => $request->file,
'agree' => $request->agree
);
Mail::send('mail', $data, function($message) use ($request,$data){
$message->to('luis#gmail.com', 'luis')->subject('Send mail ' . $request->name);
$message->from($request->email, $request->name);
if($request->hasFile('file')){
$message->attach($request->file('file')->getRealPath(), array(
'as' => $request->file('file')->getClientOriginalName(),
'mime' => $request->file('file')->getMimeType())
);
}
});
Session::flash('success', 'Mail spedita con sucesso');
}
I wish I could solve the problem
any advice? on how to do it?

Validation fails even if it has values Maatwebsite Laravel Validation

I'm currently using Maatwebsite collection when processing the import CSV file and validating it as well since I'm having hard time using the ToModel way. Here's how I validate the csv fields:
class ImportRooms implements ToCollection, WithStartRow
{
public function collection(Collection $rows)
{
foreach($rows as $row){
\Validator::make($row->toArray(), [
'name' => $row[0],
'room_code' => $row[1],
'user_name' => $row[2],
'email' => $row[3],
'password' => $row[4],
'remarks' => $row[5],
'name' => ['required', 'max:50'],
'room_code' => ['required', 'max:50'],
'user_name' => ['required', 'max:255'],
'email' => ['required', 'email', 'max:255','nullable'],
'password' => ['min:8','max:255','nullable'],
'remarks' => ['max:500'],
])->validate();
}
}
/**
* #return int
*/
public function startRow(): int
{
return 2;
}
}
This is a sample data I have.
Illuminate\Support\Collection {#565 ▼
#items: array:6 [▼
0 => "Room name"
1 => "Room101"
2 => "user"
3 => "fmacejkovic#example.org"
4 => "password"
5 => "remarks"
]
}
My problem now is that even though the values are all correct and valid, it still fails in the validation. I'm trying to assign to a specific variable so that when it fails, it'll return the row name instead of row number. Even though I use the row number, it still fails.
You have used incorrect syntax for Validator::make(), use this :
class ImportRooms implements ToCollection, WithStartRow
{
public function collection(Collection $rows)
{
foreach($rows as $row){
$row = $row->toArray();
$data = [
'name' => $row[0],
'room_code' => $row[1],
'user_name' => $row[2],
'email' => $row[3],
'password' => $row[4],
'remarks' => $row[5],
];
\Validator::make($data, [
'name' => ['required', 'max:50'],
'room_code' => ['required', 'max:50'],
'user_name' => ['required', 'max:255'],
'email' => ['required', 'email', 'max:255','nullable'],
'password' => ['min:8','max:255','nullable'],
'remarks' => ['max:500'],
])->validate();
}
}
/**
* #return int
*/
public function startRow(): int
{
return 2;
}
}
Refer https://laravel.com/docs/5.8/validation#automatic-redirection
//Convert row data into array and store it in a variable.
$row = $row->toArray();
//Set data to be validated.
$data = [
'name' => $row[0],
'room_code' => $row[1],
'user_name' => $row[2],
'email' => $row[3],
'password' => $row[4],
'remarks' => $row[5]
];
//Set conditions for validation.
$conditions = [
'name' => 'required|max:50',
'room_code' => 'required|max:50',
'user_name' => 'required|max:255',
'email' => 'required|email|max:255|nullable',
'password' => 'min:8|max:255|nullable',
'remarks' => 'max:500'
];
//Validate the excel data.
\Validator::make($data, $conditions)->validate();

mapWithKeys in laravel ,i dont understand how do it work?

I saw the example of laravel, but i dont understand how do it work.
for this example:
$collection = collect([
[
'name' => 'John',
'department' => 'Sales',
'email' => 'john#example.com'
],
[
'name' => 'Jane',
'department' => 'Marketing',
'email' => 'jane#example.com'
]
]);
$keyed = $collection->mapWithKeys(function ($item) {
return [$item['email'] => $item['name']];
});
$keyed->all();
someone can explain detail of it?
$collection = collect([
[
'name' => 'John',
'department' => 'Sales',
'email' => 'john#example.com'
],
[
'name' => 'Jane',
'department' => 'Marketing',
'email' => 'jane#example.com'
]
]);
$keyed = $collection->mapWithKeys(function ($item) {
//this line takes one array of collection object in item array and make a key of its email and store name on that email key
return [$item['email'] => $item['name']];
});
$keyed->all();

Resources