How Do I Prevent Duplicate When Storing My API Fetched Data - laravel

I am fetching data from an API. I am able to store the data in my database but whenever i refresh, it stores another copy of the same set of data fetched from the API. I simply want to know how to only update the database with the new records whilst ignoring the old once stored already.
Controller
public function dashboard()
{
$client = new Client();
$uri = 'https://api.clickmeeting.com/v1/conferences/active';
$header = ['headers' => ['X-Api-Key' => '123456']];
$res = $client->get($uri, $header);
$conferences = json_decode($res->getBody()->getContents(), true);
collect($conferences)
->each(function ($conference, $key) {
ClickMeeting::create([
'conference_id' => $conference['id'],
'parent_id' => $conference['parent_id'],
'room_type' => $conference['room_type'],
'room_pin' => $conference['room_pin'],
'name' => $conference['name'],
'name_url' => $conference['name_url'],
'access_type' => $conference['access_type'],
'lobby_enabled' => $conference['lobby_enabled'],
'lobby_description' => $conference['lobby_description'],
'registration_enabled' => $conference['registration_enabled'],
'status' => $conference['status'],
'timezone' => $conference['timezone'],
'timezone_offset' => $conference['timezone_offset'],
'paid_enabled' => $conference['paid_enabled'],
'automated_enabled' => $conference['automated_enabled'],
'type' => $conference['type'],
'permanent_room' => $conference['permanent_room'],
'room_url' => $conference['room_url'],
'embed_room_url' => $conference['embed_room_url'],
]);
});
return view('admin.clickmeeting.dashboard');
}
Migration Schema
public function up()
{
Schema::create('clickmeeting', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('conference_id')->unique();
$table->string('parent_id')->nullable();
$table->string('room_type');
$table->string('room_pin');
$table->string('name');
$table->string('name_url');
$table->string('ends_at');
$table->string('access_type');
$table->string('lobby_enabled');
$table->string('lobby_description');
$table->string('registration_enabled');
$table->string('status');
$table->string('timezone');
$table->string('timezone_offset');
$table->string('paid_enabled');
$table->string('automated_enabled');
$table->string('type');
$table->string('permanent_room');
$table->string('room_url');
$table->string('embed_room_url');
});
}
Help is gratefully appreciated. Thank You

Laravel has a firstOrCreate() method, which either finds the model or creates it. Perfect for your example. The first parameter, is the columns that defines the uniqueness and the second parameter is the columns that should be added to the row. These columns are concatenated when saved. It is very uncommon and flaky, to expect such a big request to use all columns for uniqueness.
Let's imagine that these 3 columns would define a non present composite key room_type, parent_id and room_url. This can be adjusted by you to follow the correct columns.
ClickMeeting::firstOrCreate([
'parent_id' => $conference['parent_id'],
'room_type' => $conference['room_type'],
'room_url' => $conference['room_url'],
],
[
'conference_id' => $conference['id'],
'room_pin' => $conference['room_pin'],
'name' => $conference['name'],
'name_url' => $conference['name_url'],
'access_type' => $conference['access_type'],
'lobby_enabled' => $conference['lobby_enabled'],
'lobby_description' => $conference['lobby_description'],
'registration_enabled' => $conference['registration_enabled'],
'status' => $conference['status'],
'timezone' => $conference['timezone'],
'timezone_offset' => $conference['timezone_offset'],
'paid_enabled' => $conference['paid_enabled'],
'automated_enabled' => $conference['automated_enabled'],
'type' => $conference['type'],
'permanent_room' => $conference['permanent_room'],
'embed_room_url' => $conference['embed_room_url'],
],
]);

Related

Updating a document in laravel firestore

Hi I've been trying out things in updating aa document in firestore from laravel 9. But it doesn't seem to work at all.
What I have tried so far:
$product = app('firebase.firestore')
->database()
->collection('Products')
->document('15da5077cf8940f797db')
->update([
'path' => 'status',
'value' => 'archive'
]);
and
$status = "archive";
$currentData = json_decode(json_encode([
'status' => $status,
]));
$newData = [
'status' => $status,
];
$postData = app('firebase.firestore')
->database()
->collection('Products')
->document('15da5077cf8940f797db');
$postData->update([[
'path' => 'Products',
'value' => FieldValue::arrayRemove([$currentData])
]]);
$postData->set([
'Products' => FieldValue::arrayUnion($newData)
], ['merge' => true]);
and, javascript
const app = initizalizeApp(firebaseConfig);
const db = getFirestore(app);
btnArchive.addEventListener('click', (e) =>{
archiveDoc(doc(db, "Products", "15da5077cf8940f797db"), {
status: archive,
})
alert('Product archived!')
});
I want to update the status of a product from active to archive. But this doesn't work at all. Also is there another way to edit a document without specifying it?
this is how my collection looks like, each document has its own product details:

Stripe & Laravel how to upgrade or downgrade session subscription?

I have some issues using the Laravel Cashier for creating subscriptions.
First, from my backend I am creating a Package, which calls the following two Strip functions:
public function createStripeProduct(array $data)
{
$product = $this->stripe->products->create([
'name' => $data['title']." ".appName(),
]);
return $product->id;
}
public function createStripePrice(array $data)
{
$price = $this->stripe->prices->create([
'unit_amount' => $data['price'] * $this->multiple,
'currency' => $this->currency,
'recurring' => ['interval' => 'month'],
'product' => $data['stripe_prod_id'],
]);
return $price->id;
}
Then in my Controller, I am creating the session:
public function create(Request $request)
{
$key = config('services.stripe.secret');
$stripe = new Stripe\StripeClient($key);
$stripeCustomer = $user->createOrGetStripeCustomer();
$checkout_session = $stripe->checkout->sessions->create([
'customer' => $stripeCustomer['id'],
'success_url' => route('frontend.user.account'),
'cancel_url' => route('frontend.user.account'),
'payment_method_types' => ['card'],
'line_items' => [
[
'price' => $request->stripe_price_id,
'quantity' => 1,
],
],
'mode' => 'subscription',
'allow_promotion_codes' => true,
]);
return $checkout_session['id'];
}
Everything is working so far, but with the implementation, I can subscribe one use multiple times to the same or to a different Package.
How can I prevent this from happening and also how to implement a future upgrade/downgrade of the Package?
To answer your two questions:
1) I can subscribe one use multiple times to the same or to a different Package. How can I prevent this from happening
Your code is fetching a Stripe Customer object in createOrGetStripeCustomer(). You can list all Subscriptions on the Customer with https://stripe.com/docs/api/subscriptions/list#list_subscriptions-customer and then check if you want to create an additional CheckoutSession Subscription on that Customer.
2) how to implement a future upgrade/downgrade of the Package?
You would use the code snippets here: https://stripe.com/docs/billing/subscriptions/upgrade-downgrade#changing where you update the Subscription's SubscriptionItem with a new Price ID.
$sub = \Stripe\Subscription::update('sub_123', [
'cancel_at_period_end' => false,
'proration_behavior' => 'create_prorations',
'items' => [
[
'id' => $subscription->items->data[0]->id,
'price' => 'price_456', // the new Price to update to
],
],
]);

ListEntries in table for relationship on show page - backpack for laravel

Just new with backpack. I search on official site and googled it, but dit not found an answer
In laravel 7, using Backpack 4.1
My data model is : Customer has many addresses
Relationship is configured in the Customer model :
public function addresses()
{
return $this->hasMany(\App\Models\Address::class, 'user_id');
}
Relationship is configured in the Address model :
public function customer()
{
return $this->belongsTo(\App\Models\Customer::class);
}
public function country()
{
return $this->belongsTo(\App\Models\Country::class);
}
public function address_type()
{
return $this->belongsTo(\App\Models\AddressType::class);
}
In my customer show page, I would like to show all customer addresses in a table, just under the customer details.
So in my CustomerCrudController, I have implemented this method :
protected function setupShowOperation()
{
$this->crud->set('show.setFromDb', false);
$this->crud->addColumn(['name' => 'name', 'type' => 'text', 'label' => __('models/customers.fields.name'), ]);
$this->crud->addColumn(['name' => 'email', 'type' => 'email', 'label' => __('models/customers.fields.email'), ]);
$this->crud->addColumn([
'name' => 'addresses',
'label' => __('models/addresses.plural'),
'type' => 'table',
'columns' => [
'address_type_id' => __('models/addresses.fields.address_type'),
'address_type.name' => __('models/addresses.fields.address_type'),
'address1' => __('models/addresses.fields.address1'),
'address2' => __('models/addresses.fields.address2'),
'city' => __('models/addresses.fields.address2'),
'postal_code' => __('models/addresses.fields.address2'),
'country.name' => __('models/countries.singular'),
],
]);
}
When I go on my page : /admin/customer/3/show,
In my debugbar, I saw the query how load addresses
select * from `addresses` where `addresses`.`user_id` = 3 and `addresses`.`user_id` is not null
I have the table rendered with the corresponding number of lines from data in DB, but rows are blank.
Is this the correct way to do that ? What are the correct parameters ?
Is there a way to show a table with action buttons (show entry, edit) - same as in List view ?
Should it be implemented in another way ?
Hope I'm clear.
Thanks
Don't know if it is a laravel bug, but my solution was to create my own table blade, base on the file :
\vendor\backpack\crud\src\resources\views\crud\columns\table.blade.php
and have created my own :
\resources\views\vendor\backpack\crud\columns\address_table.blade.php
I have juste changed the file:40
#elseif( is_object($tableRow) && property_exists($tableRow, $tableColumnKey) )
to
#elseif( is_object($tableRow) && isset($tableRow->{$tableColumnKey}) )
now, in my CustomerCrudController.php :
protected function setupShowOperation()
{
$this->crud->set('show.setFromDb', false);
$this->crud->addColumn(['name' => 'name', 'type' => 'text', 'label' => __('models/customers.fields.name'),]);
$this->crud->addColumn(['name' => 'email', 'type' => 'email', 'label' => __('models/customers.fields.email'),]);
$this->crud->addColumn([
'name' => 'addresses',
'label' => __('models/addresses.plural'),
'type' => 'address_table', // my custom type
'model' => \App\Models\Address::class,
'entity' => 'addresses',
'columns' => [
'address_type_name' => __('models/addresses.fields.address_type'),
'postal_code' => __('models/addresses.fields.postal_code'),
'city' => __('models/addresses.fields.city'),
'address1' => __('models/addresses.fields.address1'),
'address2' => __('models/addresses.fields.address1'),
],
]);
}
And I've added an accessor in my model (Address.php)
public function getAddressTypeNameAttribute()
{
return "{$this->address_type->name}";
}
Don't know if there is a better way ...
Hope this will help others.
I use Laravel 8,
In addition for the answer above, and based on this answer https://stackoverflow.com/a/65072393 and https://stackoverflow.com/a/43011286/1315632 regarding PHP function property_exists vs Laravel magic methods to create dynamic properties and methods
After creating the overwrite column php artisan backpack:publish crud/columns/table
I change line 40 in file:\resources\views\vendor\backpack\crud\columns\table.blade.php into
#elseif( is_object($tableRow) && ( property_exists($tableRow, $tableColumnKey) || property_exists((object)$tableRow->toArray(), $tableColumnKey) ) )
adding OR checking from answer https://stackoverflow.com/a/65072393

Verify duplicate values (multi column unique) on the array in Laravel5.7

relate as below issue
Verify duplicate values on the array in Laravel5.7
I am add two fields to data base.
// database/migrations/UpdateUsersTable.php
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('staff_no' , 10);
$table->string('staff_code');
$table->unique(['staff_no', 'staff_code']);
});
}
I want to verify if multi column unique in my database or post array value is duplicate or not?
Here is my codes :
this is my Controller
UsersController
public function MassStore(MassStoreUserRequest $request)
{
$inputs = $request->get('users');
//mass store process
User::massStore($inputs);
return redirect()->route('admin.users.index');
}
and this is my POST data (post data($inputs) will send like as below) :
'users' => [
[
'name' => 'Ken Tse',
'email' => 'ken#gamil.com',
'password' => 'ken12ken34ken',
'staff_no' => '20191201CT',
'staff_code' => 'IT-1azz',
],
[
'name' => 'Tom Yeung',
'email' => 'tom#gamil.com',
'password' => 'tom2222gt',
'staff_no' => '20191201CT', // staff_no + staff_code is duplicate, so need trigger error
'staff_code' => 'IT-1azz',
],
]
MassStoreUserRequest
public function rules()
{
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string']
// how to set verify duplicate values(staff_no,staff_code unique) in here?
];
}
You can use distinct validation rule. So your code will look like-
public function rules()
{
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string', 'distinct']
];
}
Change
`'users.*.staff_code' => ['required','string']` line to
'users.*.staff_code' => ['required','string', Rule::exists('staff')->where(function ($query) {
//condition to check if staff_code and staff_no combination is unique
return $query->where('staff_code', $request->('your_key')['staff_code'])->where('staff_no', $request->('your_key')['staff_no']) ? false : true; // You may need to make a loop if you can not specify key
}),]
I solve this problem myself.
https://laravel.com/api/5.7/Illuminate/Foundation/Http/FormRequest.html#method_validationData
main point is overrides method validationData(),make value "staff_no_code" to validation data.
Here is my codes :
MassStoreUserRequest
public function rules()
{
$validate_func = function($attribute, $value, $fail) {
$user = User::where(DB::raw("CONCAT(staff_no,staff_code )", '=', $value))
->first();
if (!empty($user->id)) {
$fail(trans('validation.alreadyExists'));
}
};
return [
'users' => ['required','array'],
'users.*.name' => ['required'],
'users.*.email' => ['required','unique:users','email', 'distinct'],
'users.*.password' => ['required','string','min:8'],
'users.*.staff_no' => ['required','size:10'],
'users.*.staff_code' => ['required','string']
// 'distinct' check when working with arrays, the field under validation must not have any duplicate values.
// $validate_func check DB exist
'users.*.staff_no_code' => ['distinct',$validate_func]
];
}
//make value "staff_no_code" to validation data
protected function validationData()
{
$inputs = $this->input();
$datas = [];
foreach ($inputs as $input ) {
$input['staff_no_code'] = $input['staff_no'] . $input['staff_code'];
$datas[] = $input;
}
return $datas;
}

Storing data to multiple tables from single form in laravel

My schemas are:
Schema::create('persons', function (Blueprint $table) {
$table->bigInteger('university_id')->unique()->unsigned();
$table->string('category');
$table->string('name');
$table->timestamps();
});
Schema::create('teachers', function (Blueprint $table) {
$table->increments('teacher_id');
$table->bigInteger('university_id')->unsigned();
$table->string('position');
$table->string('courses');
$table->integer('salary');
$table->timestamps();
});
Schema::create('students', function (Blueprint $table) {
$table->increments('student_id');
$table->bigInteger('university_id')->unsigned();
$table->string('year');
$table->string('semester');
$table->string('programme');
$table->integer('rollNum');
$table->timestamps();
});
I have a two forms with fields:
For Teachers:University ID, Name, Category, Position, Courses, Salary
For Students:University ID, Name, Category, Year, Semester, Programme, Roll Number
I tried to store data in the database through my controller in single method as follows:
After requesting all data into variables from form, I tried to store data in the following way.
University::create([
'university_id' =>$universityID,
'category' => $category,
'name' => $name
]);
//I passed values of category as Teacher when submitting from teacher form
//and Student while submitting student form.
if($category == 'Teacher'){
Teacher::create([
'university_id' => $universityID,
'position' => $position,
'courses' => $course,
'salary' => $salary
]);
}
if($category == 'Student'){
Student::create([
'university_id' => $universityID,
'year' => $year,
'semester' => $semester,
'programme' => $programme,
'rollNum' => $roll
]);
}
When i submitted Teacher's form, I was expecting that data will be stored in University and Teachers table only and it did. But there was an unexpected problem occurred. The Student table was filled with Null values. I was expecting if condition will prevent running Student::create([])
So how can I store values only in University and Teachers table when submitting from teachers form and University and Students table only when submitting from students form without having null values in either of them.
Instead of using like this, simple would be use if and else statements and that would do the job.
Example:
$university = University::create([
'university_id' =>$universityID,
'category' => $category,
'name' => $name
]);
if($category == 'Teacher') {
Teacher::create([
'university_id' => $university->id,
'position' => $position,
'courses' => $course,
'salary' => $salary
]);
else if($category == 'Student') {
Student::create([
'university_id' => $university->id,
'year' => $year,
'semester' => $semester,
'programme' => $programme,
'rollNum' => $roll
]);
}else{
//Unknown Category name
}
Let me know if that works for you. The way I see it's very simple and straight forward.

Resources