I am trying to implement an Interface into a Job but having no luck. Is it possible to implement an interface / repository within the public construct and use said interface in the handle() method of the Job?
The error I am getting is as follows:
Argument 1 passed to App\Jobs\OrderCreate::__construct() must be an instance of App\Http\Interfaces\OrderInterface, string given, called in /Users/Panoply/Sites/stock-sync/app/Http/Controllers/StockController.php on line 31
Below is a basic setup of what I am trying to achieve.
Stock Controller:
public function test(){
dispatch(new OrderCreate('hello'));
}
OrderCreate Job:
protected $order;
protected $test;
public function __construct(OrderInterface $order, $test)
{
$this->order = $order;
$this->test = $test;
}
public function handle()
{
$this->order->test($this->test);
}
OrderRepository:
class OrderRepository implements OrderInterface
{
public function test($data) {
error_log($data);
}
}
OrderInterface:
public function test($data);
I have had no troubles implementing this pattern into my controllers and commands but I can't seem to get it working on a Job.
Nevermind, the issue was I shouldn't of been calling the interface within the __construct() but instead within handle()
Editing for more detailed explanation.
The __construct() of a Laravel / Lumen Job from what I can tell only accepts data and thus implementing an interface within the __constuct() will cause my above error to be thrown.
In order to use an Interface within a job, you will need to call your interface within the handle() function.
As an example, the following will NOT work within a Job class:
protected $test;
public function __construct(InterfaceTest $test)
{
$this->test = $test;
}
This is because the Job construct does not take in Interfaces, it only takes in the data you pass in from the dispatch call. In order to use your Interface within a job, you need to call the interface within the handle() function and then it will succeed and work, example:
public function handle(InterfaceTest $test)
{
$test->fn();
}
This seems to only be the case when implementing on a Job. In most cases when you require an interface within a Controller or Command, you will implement within the __construct().
Related
So I'm really trying to figure it out how can I do that in Symfony 5.
I have an services named PaymentRequestService which have the entire logic for requests to another application (based on microservices).
I injected PaymentRequestService in PaymentService as constructor, an service which processes data, make validation, etc.
And right now I'm trying to call from my controller an method from PaymentRequestService by using PaymentService. Something like that: $paymentService->$paymentRequestService->method.
Can someone tell me how can I do that?
Right now it looks something like that $payment = $paymentRequestService->getPaymentRequest((string)$id)
But I want to eliminate PaymentRequestService.
I dont argue the architecture you want to use... but you would do it this way:
(PHP 8 syntax)
class PaymentService
public function __construct(private PaymentRequestService $requestService)
{}
public function getRequest(): PaymentRequestService
{
return $this->requestService;
}
}
class MyController extends AbstractController
{
public function myAction(PaymentService $paymentService, Request $request): Response
{
$id = $request->get('id');
$payment = $paymentService->getRequest()->getPaymentRequest((string)$id);
return new Response('done');
}
}
you also could map specific methods to dont need the cascading - but then why you dont use the RequestService directly in the first place.
That should be doable over a getter like you have implemented currently, but why not just pass the PaymentRequestService to the controller where it is used?
e.g. $paymentRequestService->method()
Services are injectable in every class inside your application and since there is (by default) only one instance of that service running, you could just autowire it to your controller.
You have to inject service directly in controller and do data validation in PaymentService. For example:
class MyController extends AbstractController
{
private PaymentRequestService $paymentRequestService;
public function __construct(PaymentRequestService $paymentRequestService)
{
$this->paymentRequestService = $paymentRequestService;
}
public function index()
{
$this->paymentRequestService->method();
}
}
I'm working on a project running an old version of Laravel (5.6). There's a lot of custom artisan commands in this project. Some of those commands should create a summary on the end of the execution. My first idea was to create a parent class, and all the commands extend from this class, something like:
<?php
abstract class ParentCommand extends Command
{
abstract protected function doYourStuff();
abstract protected function prepareSummaryData();
final public function handle()
{
$this->doYourStuff();
$this->createSummary($this->prepareSummaryData());
}
final protected function createSummary($data)
{
// Summary stuff in here...
}
}
But the problem is that Laravel does DI in the handle method, so the handle method in child classes could have a different signature, which is not allowed.. :(
Any idea of how to run something after the handle() method is executed?
What about using a trait ?
trait Summary
{
protected function createSummary($data)
{
// Summary stuff in here...
}
}
class SomeCommand extends Command
{
use Summary;
public function handle()
{
//do stuff
//prepare data to summarize
$this->createSummary($data);
}
}
How can I mock/stub a method on a model correctly (in laravel)? Currently I am trying...
$mock = Mockery::spy(Organisation::class);
$mock->shouldReceive('findByCustomerId')->once();
and the code under test is
use App\Organisation;
...
public function handle()
{
$org = Organisation::findByCustomerId(1234);
However when I run the tests I get an error Call to undefined method App\Organisation::findByCustomerId(), which tells me that the class/model is not being mocked correctly, does anyone know where I could be going wrong?
Mockery doesn't automatically overload classes when you create a mock for them (like some other libraries might do). It does support overloading, but I couldn't figure out how to overload a class with a partial mock.
So it looks like you'll have to use dependency injection to "inject" the mock object into the class that is being tested:
class TestedClass
{
private $organisation;
public function __construct(Organisation $organisation)
{
$this->organisation = $organisation;
}
public function handle()
{
$org = $this->organisation->findByCustomerId(1234);
}
}
Laravel with automatically inject the correct object for you. To inject your mock object instead of the Organization class you can do something like this in your test:
$mock = \Mockery::spy(Organization::class)->makePartial();
$mock->shouldReceive('findByCustomerId')->once();
$this->app->instance(Organization::class, $mock);
I am trying to configure test classes for my Symfony 2.7 project. I am testing a controller that uses doctrine for connecting to the data base.
I finally managed to do it extending KernelTestCase in order to avoid this Fatal error: Call to a member function "X" on a non-object. But here is the problem: I was triying to order my code and simplify 5 test functions into one by using a additionProvider:
public function additionProvider()
{
$first=$this->service->getTranslation("","en");
return array
(
'original not created' =>array($first,"")
);
}
and I want to use it like:
/**
* #dataProvider additionProvider
*/
public function testGetTranslation($expected, $actual)
{
$this->assertEquals($expected, $actual);
}
here is my setUp():
public function setUp()
{
self::bootKernel();
$this->em = static::$kernel->getContainer()
->get('doctrine')
->getManager()
;
$this->service = new \DictionaryBundle\Controller\UtilController($this->em);
}
I tried to add the first test like this and the error appeared again, like if it couldn't access to the repository. So, is possible to use addittionProviders with repository functions? how?
Thanks!
The dataProvider is executed before the setup method. So the service variable is not yet initialized.
So the dataprovider method can only return data, you need to move the call to the service in the tested method.
Here the paragraph of the doc:
Note All data providers are executed before both the call to the
setUpBeforeClass static method and the first call to the setUp method.
Because of that you can't access any variables you create there from
within a data provider. This is required in order for PHPUnit to be
able to compute the total number of tests.
Normally Eloquent model is used as following:
class Article extends Eloquent
{
// Eloquent Article implementation
}
class MyController extends BaseController
{
public function getIndex()
{
$articles = Article::all(); // call static method
return View::make('articles.index')->with('articles', $articles);
}
}
But when restructing use Dependency Injection, it looks like that:
interface IArticleRepository
{
public function all();
}
class EloquentArticleRepository implements IArticleRepository
{
public function __construct(Eloquent $article)
{
$this->article = $article;
}
public function all()
{
return $this->article->all(); // call instance method
}
}
So why we can call the static method Article::all() in form of instance method $this->article->all()?
P/S: Sorry for my bad English.
Good question.
Laravel utilize the Facade design pattern. when you call Article::all(), a lot of things happened behind the screen. First, PHP try to call the static method if it fails php immediately call a magic method _callStatic. then Laravel cleverly capture the static call and create instance of the original class.
From Laravel doc:
Facades provide a "static" interface to classes that are available in the application's IoC container. Laravel ships with many facades, and you have probably been using them without even knowing it!
More info:
http://laravel.com/docs/facades
http://usman.it/laravel-4-uses-static-not-true/