way to insert a new record, with cashier subscription? - laravel

I am searching the web today to see if I can somehow be able to add a new record to some tables whenever the user memberships renew.
let's say we have an app have (users, notifications, subscriptions ) tabes.
when he subscribe the first time, I can add a new record in notification table within the same controller, but what if I want every time he renews his subscription a new instance can be added in the notification table?

Eloquent Model Event
is the way to go, I believe.
Or if the logic is really simple, you can define it in your model class.
/**
* The "booting" method of the model.
*
* #param Builder
*/
protected static function boot()
{
parent::boot();
static::updated(function (Subscription $subscription) {
// your subscription logic here...
});
}

Related

How do i track an order using laravel lumen?

I'm integrating APIs that will be connected to an E-Commerce platform. I'm supposed to add an option to track orders, how do I do that?
Also, there's no frontend yet so I'm using postman to test all the API's.
the orders go through different locations on their way to the buyer, and I'd like the customer to now at which station their item is
php artisan make:observer OrderObserver
then something in the observer like this:
/**
* Handles the correct fields when updating
* #param Order $order
* #return void
*/
public function updating(User $user)
{
if($order->isDirty('some_column_you_use_to_change_status')) {
$someStatusTable = SomeStatusTable::where('track_id', $order->track_id)->first();
$someStatusTable->status = "whateverYOUwant";
}
}
I really don't know your logic but i think this could be something.
by the wat ->isDirty() watches if columns were changed.
you can also get the $order->getOriginal(('some_column_you_use_to_change_status')
I use this for example history of a Model to register history or even set new versions in my models

Laravel Cashier - Cancel a subscription using the stripe id

I'm using Laravel Cashier with stripe payment. One user can have multiple subscriptions. User should able to cancel particular subscription. Is there anyway to cancel subscription by stripe id or plan id?
You can use the PHP Stripe library to do it.
To cancel immediately
$sub = Stripe\Subscription::retrieve($subscription_id);
$sub->cancel();
To cancel after current period end
$sub = Stripe\Subscription::update($subscription_id, [
'cancel_at_period_end' => true
]);
You can use it with Laravel Cashier using subscription id .
In Laravel
You can find the subscription id in the subscriptions table in your database.(column name is stripe_id)
$subscription = \Stripe\Subscription::retrieve($subscription_id);
If you pass the correct subscription id , you will get the subscription details
To cancel the subscription
$sub->cancel();
Update your subscriptions table for the particular subscription id (again column name is stripe_id). In my
\Stripe\Subscription::where('stripe_id', $sub->id)
->update([
'trial_ends_at' => Carbon::now()->toDateTimeString(),
]);
I'm sure this is documented somewhere, but for the life of me I can't find it, but, if you pass the stripe subscription id in as the 2nd parameter you can cancel any subscription the Laravel way...
$user->subscription('default', 'price_abcdefghi12345')->cancel();
You can just call the cancel() method directly on your subscription:
$subscription->cancel();
As you can see here (Github Reference), the method $this->subscription called from your User model just gets a Subscription instance filtering by name:
/**
* Get a subscription instance by name.
*
* #param string $name
* #return \Laravel\Cashier\Subscription|null
*/
public function subscription($name = 'default')
{
return $this->subscriptions->where('name', $name)->first();
}
And, as you can see (Github Reference), the Subscription model has its own cancel method:
/**
* Cancel the subscription at the end of the billing period.
*
* #return $this
*/
public function cancel()
{
// ...
}
So, you can always call it directly on the Subscription instance.
You don't need to have the id to cancel.
You can just call
$subscription->cancel();
and it will work. If you have multiple subscriptions which you would like to cancel at the same time. You can do this. Let's find all the active subscriptions. You can find all the scopes here
$subscriptions = $user->subscriptions()->active()->get(); // getting all the active subscriptions
$subscriptions->map(function($subscription) {
$subscription->cancel(); // cancelling each of the active subscription
});
You can do this by using the cashier Subscription model as like Laravel model
Cancel Subscription
$subscription = Subscription::where('name', 'default')->where('user_id', auth()->id())->first();
$subscription->cancel();
Resume Subscription
$subscription = Subscription::where('name', 'default')->where('user_id', auth()->id())->first();
$subscription->resume();

Attaching many to many relations while still binding to created event

So I've run into this issue a few times and now I've decided that I want to find a better solution.
For examples sake, I have two models, Order & Product. There is a many to many relation so that an order can have multiple products and a product can of course have multiple orders. Table structure looks like the below -
orders
id
more fields...
products
id
more fields...
product_orders
order_id
product_id
So when an order is created I run the following -
$order = Order::create($request->validated())
$order->products()->attach([1,2,3,4...]);
So this creates an order and attaches the relevant products to it.
However, I want to use an observer, to determine when the order is created and send out and perform related tasks off the back (send an order confirmation email, etc.) The problem being, at the time the order created observer is triggered, the products aren't yet attached.
Is there any way to do the above, establishing all the many to many relationships and creating the order at the same time so I can access linked products within the Order created observer?
Use case 1
AJAX call hits PUT /api/order which in turn calls Order::place() method. Once an order is created, an email is sent to the customer who placed the order. Now I could just put an event dispatch within this method that in turn triggers the email send but this just feels a bit hacky.
public static function place (SubmitOrderRequest $request)
{
$order = Order::create($request->validated());
$order->products()->attach($request->input('products'));
return $order;
}
Use case 2
I'm feature testing to make sure that an email is sent when an order is created. Now, this test passes (and email sends work), but it's unable to output the linked products at this point in execution.
/**
* #test
**/
public function an_email_is_sent_on_order_creation()
{
Mail::fake();
factory(Order::class)->create();
Mail::assertSent(OrderCreatedMailable::class);
}
Thanks,
Chris.
I think the solution to your problem could be transaction events as provided by this package from fntneves.
Personally, I stumbled upon the idea of transactional events for another reason. I had the issue that my business logic required the execution of some queued jobs after a specific entity had been created. Because my entities got created in batches within a transaction, it was possible that an event was fired (and the corresponding event listener was queued), although the transaction was rolled back because of an error shortly after. The result were queued listeners that always failed.
Your scenario seems comparable to me as you don't want to execute your event listeners immediately due to missing data which is only attached after the model was actually created. For this reason, I suggest wrapping your order creation and all other tasks that manipulate the order within a transaction. Combined with the usage of said package, you can then fire the model created event as the actual event listener will only be called after the transaction has been committed. The code for all this basically comes down to what you already described:
DB::transaction(function() {
$order = Order::create($request->validated());
$order->products()->attach($request->input('products'));
});
In your model, you'd simply define an OrderCreated event or use an observer as suggested in the other answer:
class Order
{
protected $dispatchesEvents = [
'created' => OrderCreated::class,
];
}
class OrderCreated implements TransactionalEvent
{
public $order;
/**
* Create a new event instance.
*
* #param \App\Order $order
* #return void
*/
public function __construct(Order $order)
{
$this->order = $order;
}
}
You can redefine boot method in your model, if product ids is static
class Order extends Eloquent {
protected static function boot() {
parent::boot();
static::saving(function ($user) {
$this->products()->attach([1,2,3,4...]);
});
}
}
Or use observers
class OrderObserver
{
public function created($model)
{
//
}
}
And register this
class EventServiceProvider extends ServiceProvider
{
public function boot(DispatcherContract $events)
{
parent::boot($events);
Order::observe(new OrderObserver());
}
}

Laravel Nova - Save multiple rows to database on create

I'm converting a Laravel app that was using Backpack across to Laravel Nova.
One of my models Images allows the user to add multiple images with a base set of information from the initial form. The form in this instance asks how many images are in the series via a dropdown and then has a number of relevant fields that will be used for all of the new images being added. When saving, in the controller, I'm using the following eloquent feature to run a number of tasks and insert the required number of rows:
public function store(StoreRequest $request){
//Get some info
//Make some tweaks
//Use for loop to save multiple records
for ($k = 0; $k < $addim; $k++){
//Do some stuff
parent::storeCrud(${"request"});
}
}
This works perfectly and inserts however many records are required.
In Laravel Nova, I can't see a way to use this same approach. Using an event listener in the model doesn't seem like the right way to save multiple records and I can't find any reference to a controller function I can use to achieve this.
I would really appreciate some thoughts and guidance on the best way to complete this part.
If someone has stumbled upon this type of problem.
You can use Laravel Observers.
In order to restrict the event to be fired only when resource is created and only using nova you can declare Observer in NovaServiceProvider.php as follows
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
parent::boot();
Nova::serving(function () {
Image::observe(ImageObserver::class);
});
}
Above code will only be triggered when your image object is modified using nova system only.
For ref Observer code will look like following
<?php
namespace App\Observers;
use App\Models\Document;
class ImageObserver
{
/**
* Handle the Image "created" event.
*
* #param \App\Models\Image $image
* #return void
*/
public function created(Image $image)
{
//logic to create multiple records
}
}
You can use the saving event in an observable
https://laravel.com/docs/5.8/eloquent#events

Observe customer account verification event in Magento

Is there a way to catch the event when the customer verifies it's account? I need this feature to enable user's access to other integrated subsystem
Since confirmAction() doesnt seem to fire any events in
/app/code/core/Mage/Customer/controllers/AccountController.php
You could do either
Overriding Frontend Core Controllers to create you own event using Mage::dispatchEvent() or add code directly to confirmAction in AccountController.php
Use #Pavel Novitsky answer but you may need to check that you are on the confirm account controller or check for the changing of email verification flag, because this event will trigger every time a customer information is change/updated
eg
public function myObserver(Varien_Event_Observer $observer)
{
if(Mage::app()->getRequest()->getControllerName() == '....account_confirm'){
$customer = $observer->getCustomer();
....
}
}
Every model has standard load_before, load_after, save_before, save_after, etc. events. Look at the Mage_Core_Model_Abstract to get the list of all predefined events.
For customers you can use customer_save_after event. In observer check original data vs new data:
public function myObserver(Varien_Event_Observer $observer)
{
$customer = $observer->getCustomer();
$orig_active_flag = $custoner->getOrigData('is_active');
$new_active_flag = $customer->getData('is_active');
// do something here …
return $this;
}
Even you can create your own event after customer vefication using below code.
Mage::dispatchEvent('Yuor_Unique_Event_Name', array());
Now using this event you can do anything you want.

Resources