Laravel Call to Undefined Method Stripe\Plan::all() - laravel

This is my Laravel code but I think I might be using an older version of the Stripe function. That's why I'm getting this error, can anyone help me with this, please?
<?php
use Illuminate\Support\Facades\Cache;
use Stripe\Stripe;
class Plan
{
public static function getStripePlans()
{
// Set the API Key
Stripe::setApiKey(User::getStripeKey());
try {
// Fetch all the Plans and cache it
return Cache::remember('stripe.plans', 60 * 24, function () {
return \Stripe\Plan::all()->data;
});
} catch (\Exception $e) {
return false;
}
}
}

If you're using a version of the Stripe-PHP library < 2.0, you'd likely need to call Stripe_Plan::all() instead of \Stripe\Plan::all()
That said, it may be helpful to upgrade to a newer version of the Stripe PHP library to take advantage of more recent features https://github.com/stripe/stripe-php

Related

Laravel implement assertSentFrom specific address Mailable Testing

Trying to get to grips with Mocking and test cases, I want to test that a Mailable TestMail is sent from company#company.com, the documentation provides hasTo, hasCc, and hasBcc but doesn't look like it uses something like hasFrom. Is there any solutions to this?
https://laravel.com/docs/9.x/mocking#mail-fake
public function testEmailAlwaysFrom()
{
Mail::fake();
Mail::to('foo#bar.com')->send(new TestMail);
Mail::assertSent(TestMail::class, function ($mail) {
return assertEquals('company#company.com', $mail->getFrom());
// return $mail->hasTo($user->email) &&
// $mail->hasCc('...') &&
// $mail->hasBcc('...');
});
}
MailFake doesn't provide hasFrom method in the class and therefore will return false.
The workaround below however doesn't work when using the environmental variable MAIL_FROM_ADDRESS, ->from() has to be called within build().
A couple of GitHub issues have been reported suggesting a workaround below:
https://github.com/laravel/framework/issues/20056
https://github.com/laravel/framework/issues/20059
public function testEmailAlwaysFrom()
{
Mail::fake();
Mail::to('foo#bar.com')
->send(new TestMail);
Mail::assertSent(TestMail::class, function ($mail) {
$mail->build(); // <-- workaround
return $mail->hasTo('foo#bar.com') and
$mail->hasFrom('company#company.com');
});
}

Laravel 8 - Conditionally remember a value in cache [duplicate]

I'm developing one of my first applications with the Laravel 4 framework (which, by the way, is a joy to design with). For one component, there is an AJAX request to query an external server. The issue is, I want to cache these responses for a certain period of time only if they are successful.
Laravel has the Cache::remember() function, but the issue is there seems to be no "failed" mode (at least, none described in their documentation) where a cache would not be stored.
For example, take this simplified function:
try {
$server->query();
} catch (Exception $e) {
return Response::json('error', 400);
}
I would like to use Cache::remember on the output of this, but only if no Exception was thrown. I can think of some less-than-elegant ways to do this, but I would think that Laravel, being such an... eloquent... framework, would have a better way. Any help? Thanks!
This is what worked for me:
if (Cache::has($key)) {
$data = Cache::get($key);
} else {
try {
$data = longQueryOrProcess($key);
Cache::forever($key, $data); // only stored when no error
} catch (Exception $e) {
// deal with error, nothing cached
}
}
And of course you could use Cache::put($key, $data, $minutes); instead of forever
I found this question, because I was looking for an answer about this topic.
In the meanwhile I found a solution and like to share it here:
(also check out example 2 further on in the code)
<?php
/**
* Caching the query - Example 1
*/
function cacheQuery_v1($server)
{
// Set the time in minutes for the cache
$minutes = 10;
// Check if the query is cached
if (Cache::has('db_query'))
{
return Cache::get('db_query');
}
// Else run the query and cache the data or return the
// error response if an exception was catched
try
{
$query = $server->query(...);
}
catch (Exception $e)
{
return Response::json('error', 400);
}
// Cache the query output
Cache::put('db_query', $query, $minutes);
return $query;
}
/**
* Caching the query - Example 2
*/
function cacheQuery_v2($server)
{
// Set the time in minutes for the cache
$minutes = 10;
// Try to get the cached data. Else run the query and cache the output.
$query = Cache::remember('db_query', $minutes, function() use ($server) {
return $server->query(...);
});
// Check if the $query is NULL or returned output
if (empty($query))
{
return Response::json('error', 400);
}
return $query;
}
I recommend you to use Laravel's Eloquent ORM and/or the Query Builder to operate with the Database.
Happy coding!
We're working around this by storing the last good value in Cache::forever(). If there's an error in the cache update callback, we just pull the last value out of the forever key. If it's successful, we update the forever key.

Handle Exception From Within Method

I am implementing payments for my website using the API of an external service (ie. the service of the payment provider).
Let's say the user clicks 'BUY', and then we go to my controller which says something along the lines of:
public function buyFunction() {
$result = $this->ExternalService->pay();
if ($result->success == true) {
return 'We are happy';
}
}
I have also created the aforementioned externalService which has the pay() method:
class ExternalService {
public function pay() {
response = //Do stuff with Guzzle to call the API to make the payment
return response;
}
}
Now, sometimes things go wrong.
Let's say the API returns an error - which means that it throws a GuzzleException - how do I handle that?
Ideally, if there is an error, I would like to log it and redirect the user to a page and tell him that something went wrong.
What I've tried
I have tried using a try/catch statement within the pay() function and using abort(500) but this doesn't allow me to redirect to the page I want to.
I have tried using a try/catch statement within the pay() function and using return redirect('/mypage') but this just returns a Redirect object to the controller, which then fails when it tries to call result->success
I have tried using number 2 but also adding a try/catch block to the controller method, but nothing changed.
In the end, I have found two solutions. In both, I use a try/catch block inside the pay() method. Then I either return 0; and check in the controller if (result == 0) or I use abort( redirect('/mypage') ); inside the try/catch block of the pay() method.
What is the right way to handle this?
How to use the try/catch blocks?
In my experience, avoid handling exceptions let them pass through and handle them accordingly with try catches. This is the most pragmatic approach. Alternatively you will end up checking result is correct in weird places, eg. if ($result) {...}. Just assume it went good, except if the exception is thrown. Bonus: never do Pokemon catches with Exception $e unless you specifically needs it!
class ExternalService {
public function pay() {
try {
response = $client->get(...);
} catch (BadResponseException $exception) {
Log::warning('This should not happen check payment api: ' . $exception->getMessage());
throw new PaymentException('Payment did not go through');
}
return response;
}
}
Assuming you have your own Exception.
class PaymentException extends HttpException
{
public function __construct(?\Exception $previous = null)
{
parent::__construct(Response::HTTP_BAD_REQUEST, 'Unexpected error processing the payment', $previous);
}
}
This enables you to handle the flow in a controller, where it would make sense to handle the redirect. Sometimes if the exception is very integral or common to the web app, it can also be handled by the exception handler instead.
class PaymentController {
public function pay(PaymentService $service) {
try {
$payment = $service->buyFunction();
} catch (PaymentException $exception) {
return redirect()->route('app.payment.error');
}
return view('app.payment.success', compact('payment'));
}
}

How to mock a Job object in Laravel?

When it comes to Queue testing in Laravel, I use the provided Queue Fake functionality. However, there is a case where I need to create a Mock for a Job class.
I have the following code that pushes a job to a Redis powered queue:
$apiRequest->storeRequestedData($requestedData); // a db model
// try-catch block in case the Redis server is down
try {
App\Jobs\ProcessRunEndpoint::dispatch($apiRequest)->onQueue('run');
$apiRequest->markJobQueued();
} catch (\Exception $e) {
//handle the case when the job is not pushed to the queue
}
I need to be able to test the code in the catch block. Because of that, I'm trying to mock the Job object in order to be able to create a faker that will throw an exception.
I tried this in my Unit test:
ProcessRunEndpoint::shouldReceive('dispatch');
That code returns: Error: Call to undefined method App\Jobs\ProcessRunEndpoint::shouldReceive().
I also tried to swap the job instance with a mock object using $this->instance() but it didn't work as well.
That said, how can I test the code in the catch block?
According to the docs, you should be able to test jobs through the mocks provided for the Queue.
Queue::assertNothingPushed();
// $apiRequest->storeRequestedData($requestedData);
// Use assertPushedOn($queue, $job, $callback = null) to test your try catch
Queue::assertPushedOn('run', App\Jobs\ProcessRunEndpoint::class, function ($job) {
// return true or false depending on $job to pass or fail your assertion
});
Making the line App\Jobs\ProcessRunEndpoint::dispatch($apiRequest)->onQueue('run'); throw an exception is a bit complicated. dispatch() just returns an object and onQueue() is just a setter. No other logic is done there. Instead, we can make everything fail by messing with the configuration.
Instead of Queue::fake();, override default queue driver with one that just won't work: Queue::setDefaultDriver('this-driver-does-not-exist'); This will make every job dispatch fail and throw an ErrorException.
Minimalist example:
Route::get('/', function () {
try {
// Job does nothing, the handle method is just sleep(5);
AJob::dispatch();
return view('noError');
} catch (\Exception $e) {
return view('jobError');
}
});
namespace Tests\Feature;
use App\Jobs\AJob;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class AJobTest extends TestCase
{
/**
* #test
*/
public function AJobIsDispatched()
{
Queue::fake();
$response = $this->get('/');
Queue::assertPushed(AJob::class);
$response->assertViewIs('noError');
}
/**
* #test
*/
public function AJobIsNotDispatched()
{
Queue::setDefaultDriver('this-driver-does-not-exist');
$response = $this->get('/');
$response->assertViewIs('jobError');
}
}
I found a solution. Instead of using a facade for adding a job to the queue (App\Jobs\ProcessRunEndpoint::dispatch($apiRequest)->onQueue('run');), I injected it into the action of the controller:
public function store(ProcessRunEndpoint $processRunEndpoint)
{
// try-catch block in case the Redis server is down
try {
$processRunEndpoint::dispatch($apiRequest)->onQueue('run');
} catch (\Exception $e) {
//handle the case when the job is not pushed to the queue
}
}
With this, the job object is resolved from the container, so it can be mocked:
$this->mock(ProcessRunEndpoint::class, function ($mock) {
$mock->shouldReceive('dispatch')
->once()
->andThrow(new \Exception());
});
Although still not sure why the shouldReceive approach doesn't work for the facade: https://laravel.com/docs/8.x/mocking#mocking-facades

Check if request was sent by Ajax or not

I am overriding a magento controller, before processing, is there a way to know if the request was sent by Ajax or not?
Thanks
Magento uses the class Zend_Controller_Request_Http for its requests.
You can use
if ($this->getRequest()->isXmlHttpRequest()) {
// is Ajax request
}
to detect Ajax requests this way.
At least
Prototype
Scriptaculous
jQuery
YUI
MochiKit
send the HTTP_X_REQUESTED_WITH header, according to the ZF docs.
Note though, "Ajax requests" means requests sent using XmlHttpRequest (and not using techniques like hidden <iframe>s, or Flash uploaders, or the like) to me.
Since this is subjective and your perception may differ: Magento itself seems to define "Ajax" in some more extended way than I do. Have a look at Mage_Core_Controller_Request_Http::isAjax():
public function isAjax()
{
if ($this->isXmlHttpRequest()) {
return true;
}
if ($this->getParam('ajax') || $this->getParam('isAjax')) {
return true;
}
return false;
}
Depending on your personal perception of "Ajax", this may (or may not) better fit your needs.
If Im not mistaken, magento is written using Zend Framework, therefor by using the Request object you can do
if($this->getRequest()->isXmlHttpRequest()){
// ajax
} else {
// not ajax
}
http://framework.zend.com/manual/en/zend.controller.request.html#zend.controller.request.http.ajax
Good luck! :)
Magento internally uses a mix of of both.
Zend Framework's isXmlHttpRequest() checks header.
public function isXmlHttpRequest(){
return ($this->getHeader('X_REQUESTED_WITH') == 'XMLHttpRequest');
}
In some cases magento uses isXmlHttpRequest() like in Mage_ImportExport_Adminhtml_ExportController::getFilterAction()
if ($this->getRequest()->isXmlHttpRequest() && $data) {
//code
}
In other cases it checks get parameter like in Mage_Catalog_Product_CompareController::removeAction()
if (!$this->getRequest()->getParam('isAjax', false)) {
$this->_redirectReferer();
}
Request Mage_Core_Controller_Request_Http::isAjax() checks for both
public function isAjax()
{
if ($this->isXmlHttpRequest()) {
return true;
}
if ($this->getParam('ajax') || $this->getParam('isAjax')) {
return true;
}
return false;
}
I would suggest to use Request object isAjax as it checks for Both.
The best mehtod is :
if (!$this->getRequest()->isAjax()) {
return false;
}
Just use pure PHP and never care:
public function isAjax()
{
return (boolean)((isset($_SERVER['HTTP_X_REQUESTED_WITH'])) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'));
}
You can use this:
if ($this->getRequest()->getParam('ajax')){
//Ajax related code
} else {
//Non ajax
}

Resources