cashier/stripe subscription not adding complete data in DB - laravel

I'm trying to create a subscription with cashier. it was working fine yesterday but now there's a problem and i don't know what changed. the problem is subscription is being created on stripe and correct data is returned but not all data is added in subscriptions table. The problem is in this function.
// dd($this->name,$subscription->id,$this->plan,$this->quantity,$trialEndsAt);
dd('builder',$this->owner->subscriptions()->create([
'name' => $this->name,
'stripe_id' => $subscription->id,
'stripe_plan' => $this->plan,
'quantity' => $this->quantity,
'trial_ends_at' => $trialEndsAt,
'ends_at' => null,
]));
You see the above commented dd() shows all data but after create(); it only shows
#attributes: array:4 [▼
"user_id" => 18
"updated_at" => "2020-12-19 12:24:04"
"created_at" => "2020-12-19 12:24:04"
"id" => 46
]
these 4 columns. Now what other thing changed was this was also happening in users table when registering a new user and i solved that with
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
}
I think it stoped working after this. I tried removing it , also adding it to subscriptions model but nothing works. HEELLLPPPP
EDIT: I noticed that this create function is working but just not adding my given values.I did include fillable array and as I said it was working before.

Related

UPSERT with Push

I am trying to achieve an upsert with push in Laravel using MongoDB.
Basically, I am saving the number of likes from a YouTube post. If the record already exists, I would like to push to an array called 'history'; otherwise, I would like to create the record with all the post details.
Does anyone have any idea how I can achieve this?
I am using this package for the connection with MongoDB.
https://github.com/jenssegers/laravel-mongodb/
Thanks.
This is what I want to achieve more precisely:
https://user-images.githubusercontent.com/44676430/154502252-0c3dcef4-9bdd-49ae-86fd-3076bc37bbc7.png
here is an example, the name and author are the key and the quantity is the value.
DB::table('books')->upsert([
[
'name' => 'J.K. Rowling',
'author' => 'Harry Potter',
'quantity' => 15
],
[
'name' => 'Cal Newport',
'author' => 'Deep Work',
'quantity' => 20
]
], ['name', 'author'], ['quantity']);

Laravel : Countries with Laravel Analytics

I'm using Laravel Analytics to get data of the visitors of my application.
In my Google Analytics dashboard, every page have it own visits numbers, unique visitors, countries of visitors etc .. like in this image :
In my web.php, I'm creating a route to test the package :
Route::get('/data', function () {
$analyticsData = Analytics::fetchMostVisitedPages(Period::days(7));
dd($analyticsData);
});
This route returns :
Illuminate\Support\Collection {#1564 ▼
#items: array:3 [▼
0 => array:3 [▼
"url" => "/new"
"pageTitle" => "test"
"pageViews" => 1534
]
1 => array:3 [▼
"url" => "/"
"pageTitle" => "test"
"pageViews" => 450
]
2 => array:3 [▼
"url" => "/customize/8"
"pageTitle" => "test"
"pageViews" => 196
]
As you can see the returned array have only url, pageTitle and pageViews. How can I add additional informations in the returned array such as countries or geographic localisation as shown in the first image ?
I've never used the package, but reading the docs, something like this will do.
The package docs state you can use any query you want, and the Google Analytics docs give an example of getting session by location.
public function myCustomMethod($maxResults = 20)
{
$response = $this->performQuery(
$period,
'ga:sessions', // metrics
[
'dimensions' => 'ga:country',
'sort' => '-ga:sessions',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
// Do something with the rows that are returned.
// I'm not sure how they're returned from the main response.
]);
}
Note, this is completely untested, you might want to fiddle with some of the data here.
Assuming I understand the documentation, this will get all countries (dimensions), it will use sessions (ga:sessions from second parameter) to measure the countries data.
It'll then just sort and get a maximum number of results.
You could change the metrics to ga:pageviews, but it's ultimately down to you what queries you want to use.
I've linked the documentation so you can find them out yourself.
You're using spatie/laravel-analytics package.
As you can see here: spatie laravel analytics - Analytics.php the fetchMostVisitedPages method that you are calling only returns that data.
Please take a look in github to see more information about this package.
fetchMostVisitedPages method:
public function fetchMostVisitedPages(Period $period, int $maxResults = 20): Collection
{
$response = $this->performQuery(
$period,
'ga:pageviews',
[
'dimensions' => 'ga:pagePath,ga:pageTitle',
'sort' => '-ga:pageviews',
'max-results' => $maxResults,
],
);
return collect($response['rows'] ?? [])->map(fn (array $pageRow) => [
'url' => $pageRow[0],
'pageTitle' => $pageRow[1],
'pageViews' => (int) $pageRow[2],
]);
}

Laravel updateOrCreate Timestamp Updating Issue

I am using the updateOrCreate method to check whether data has been changed from a response which is entered in the DB. If the record is new then it successfully adds the correct timestamp. However, I have noticed that the updated timestamp updates record for all of the records. I want this to only update if records have been updated.
But looking at the issue I believe all the records are being updated regardless.
if (isset($customers->Data)) {
foreach ($customers as $customerData) {
if ($customer = $customerData->attributes()) {
if ((string) $customer->CustomerType !== 'A') continue;
if ((string) $customer->CustomerEmail === '') continue;
$customerDb = $this::updateOrCreate(
[
'email' => $customer->CustomerEmail,
'code' => $customer->Customer,
'currency' => $customer->Currency,
],
[
'email' => $customer->CustomerEmail,
'code' => $customer->Customer,
'currency' => $customer->Currency,
'name' => $customer->CustomerName,
'phone' => $customer->CustomerPhone,
'terms' => $customer->Terms,
]
);
}
}
}
The email, code, currency fields will always be unique and the rest to create if these are not present. Should the default behavior be that it updates regardless? What I want to achieve is to only detect if a record has been changed if it has then updated that particular field and update the timestamp if it's not there then create it. Thus filtering out what has been updated and only show these records rather than the whole table.
Sorry but new to Laravel any guidance is welcome thank you.

Laravel 5.6. How to test JSON/JSONb columns

$this->assertDatabaseHas() not working with JSON/JSONb columns.
So how can I tests these types of columns in Laravel?
Currently, I have a store action. How can I perform an assertion, that a specific column with pre-defined values was saved.
Something like
['options->language', 'en']
is NOT an option, cause I have an extensive JSON with meta stuff.
How can I check the JSON in DB at once?
UPD
Now can be done like that.
I have solved it with this one-liner (adjust it to your models/fields)
$this->assertEquals($store->settings, Store::find($store->id)->settings);
Laravel 7+
Not sure how far back this solution works.
I found out the solution. Ignore some of the data label, Everything is accessible, i was just play around with my tests to figure it out.
/**
* #test
*/
public function canUpdate()
{
$authUser = UserFactory::createDefault();
$this->actingAs($authUser);
$generator = GeneratorFactory::createDefault();
$request = [
'json_field_one' => [
'array-data',
['more-data' => 'cool'],
'data' => 'some-data',
'collection' => [
['key' => 'value'],
'data' => 'some-more-data'
],
],
'json_field_two' => [],
];
$response = $this->putJson("/api/generators/{$generator->id}", $request);
$response->assertOk();
$this->assertDatabaseHas('generators', [
'id' => $generator->id,
'generator_set_id' => $generator->generatorSet->id,
// Testing for json requires arrows for accessing the data
// For Collection data, you should use numbers to access the indexes
// Note: Mysql dose not guarantee array order if i recall. Dont quote me on that but i'm pretty sure i read that somewhere. But for testing this works
'json_field_one->0' => 'array-data',
'json_field_one->1->more-data' => 'cool',
// to access properties just arrow over to the property name
'json_field_one->data' => 'some-data',
'json_field_one->collection->data' => 'some-more-data',
// Nested Collection
'json_field_one->collection->0->key' => 'value',
// Janky way to test for empty array
// Not really testing for empty
// only that the 0 index is not set
'json_field_two->0' => null,
]);
}
Note: The below solution is tested on Laravel Version: 9.x and Postgres version: 12.x
and the solution might not work on lower version of laravel
There would be two condition to assert json column into database.
1. Object
Consider Object is in json column in database as shown below:
"properties" => "{"attributes":{"id":1}}"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->attributes->id"=>1
]);
2. Array
Consider array is in json column as shown below:
"properties" => "[{"id":1},{"id":2}]"
It can assert as
$this->assertDatabaseHas("table_name",[
"properties->0->id"=>1,
"properties->1->id"=>2,
]);
Using json_encode on the value worked for me:
$this->assertDatabaseHas('users', [
'name' => 'Gaurav',
'attributes' => json_encode([
'gender' => 'Male',
'nationality' => 'Indian',
]),
]);

Will Model::updateOrCreate() update a soft-deleted model if the criteria matches?

Let's say I have a model that was soft-deleted and have the following scenario:
// EXISTING soft-deleted Model's properties
$model = [
'id' => 50,
'app_id' => 132435,
'name' => 'Joe Original',
'deleted_at' => '2015-01-01 00:00:00'
];
// Some new properties
$properties = [
'app_id' => 132435,
'name' => 'Joe Updated',
];
Model::updateOrCreate(
['app_id' => $properties['app_id']],
$properties
);
Is Joe Original now Joe Updated?
OR is there a deleted record and a new Joe Updated record?
$variable = YourModel::withTrashed()->updateOrCreate(
['whereAttributes' => $attributes1, 'anotherWhereAttributes' => $attributes2],
[
'createAttributes' => $attributes1,
'createAttributes' => $attributes2,
'createAttributes' => $attributes3,
'deleted_at' => null,
]
);
create a new OR update an exsiting that was soft deleted AND reset the softDelete to NULL
updateOrCreate will look for model with deleted_at equal to NULL so it won't find a soft-deleted model. However, because it won't find it will try to create a new one resulting in duplicates, which is probably not what you need.
BTW, you have an error in your code. Model::updateOrCreate takes array as first argument.
RoleUser::onlyTrashed()->updateOrCreate(
[
'role_id' => $roleId,
'user_id' => $user->id
],
[
'deleted_at' => NULL,
'updated_at' => new \DateTime()
])->restore();
Like this you create a new OR update an exsiting that was soft deleted AND reset the softDelete to NULL
Model::withTrashed()->updateOrCreate([
'foo' => $foo,
'bar' => $bar
], [
'baz' => $baz,
'deleted_at' => NULL
]);
Works as expected (Laravel 5.7) - updates an existing record and "undeletes" it.
I tested the solution by #mathieu-dierckxwith Laravel 5.3 and MySql
If the model to update has no changes (i.e. you are trying to update with the same old values) the updateOrCreate method returns null and the restore() gives a Illegal offset type in isset or empty
I got it working by adding withTrashed so that it will include soft-deleted items when it tries to update or create. Make sure deleted_at is in the fillable array of your model.
$model = UserRole::withTrashed()->updateOrCreate([
'creator_id' => $creator->id,
'user_id' => $user->id,
'role_id' => $role->id,
],[
'deleted_at' => NULL
])->fresh();
try this logic..
foreach ($harga as $key => $value) {
$flight = salesprice::updateOrCreate(
['customerID' => $value['customerID'],'productID' => $value['productID'], 'productCode' => $value['productCode']],
['price' => $value['price']]
);
}
it work for me

Resources