Getting error "Argument 1 passed to Modules\\Admin\\Events\\" - php

I am new in laravel. I am creating mailer in laravel in which i created event for it. But from postman when i am hitting the api, i am getting error:
Argument 1 passed to Modules\\Admin\\Events\\NewsLetterSubscribeEvent::__construct() must be an instance of App\\Models\\NewsletterSubscription, array given, called in /home/ashish/projects/backend/laravel-backend/app/Repositories/NewsletterSubscriptionRepository.php on line 25",
What can be issue, i imported all classes, but still getting the error.
this is my code
repository
class NewsletterSubscriptionRepository extends EloquentBaseRepository
{
public $model = NewsletterSubscription::class;
public function create($data)
{
try{
DB::beginTransaction();
event(new NewsLetterSubscribeEvent($data));
DB::commit();
} catch(Exception $exception){
DB::rollBack();
throw $exception;
}
return parent::create($data); // TODO: Change the autogenerated stub
}
}
event file
<?php
namespace Modules\Admin\Events;
use App\Models\NewsletterSubscription;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use Modules\Admin\Mail\NewsLetterSubscribeMail;
class NewsLetterSubscribeEvent
{
use Dispatchable, InteractsWithSockets, SerializesModels;
/**
* SendMailToAgentEvent constructor.
* #param User $user
*/
public function __construct(NewsletterSubscription $user)
{
dd($user);
Mail::to($user->email)->send(new NewsLetterSubscribeMail($user));
}
}
model
<?php
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
class NewsletterSubscription extends Model
{
const ACTIVE = 1;
const INACTIVE = 0;
protected $table = 'newsletter_subscription';
protected $casts = [
'is_active' => 'int'
];
protected $fillable = [
'email',
'is_active'
];
}
Am i forgetting any namespace, or i am doing something wrong? Thanks in advance.

Error is saying must be an instance of NewsletterSubscription but you are passing array to fix this
public function __construct($user) // remove NewsletterSubscription from here
{
dd($user);
Mail::to($user->email)->send(new NewsLetterSubscribeMail($user));
}
or
class NewsletterSubscriptionRepository extends EloquentBaseRepository
{
public $model = NewsletterSubscription::class;
public function create($data)
{
$newsLetterSubscribeEvent = null;
try{
DB::beginTransaction();
$newsLetterSubscribeEvent = NewsletterSubscription::create($data); // TODO: Change the autogenerated stub
event(new NewsLetterSubscribeEvent($newsLetterSubscribeEvent)); // passing model instace
DB::commit();
} catch(Exception $exception){
DB::rollBack();
throw $exception;
}
return $newsLetterSubscribeEvent;
}
}

Related

Conditional broadcastWith in Laravel Event?

I have an event that would dispatch information on multiple channels:
A channel for members
A channel for managers
I wrote this:
<?php
class ModelUpdated implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $model;
public function __construct(Model $model)
{
$this->model = $model;
}
public function broadcastWith($who)
{
if ($who == "model.{$this->model->id}")
return [$this->model->id];
else if ($who == "model.{$this->model->id}.managers")
return [$this->model];
else
return [];
}
public function broadcastOn()
{
return [
new PrivateChannel("model.{$this->model->id}"),
new PrivateChannel("model.{$this->model->id}.managers")
];
}
}
Unfortunately, the broadcastWith doesn't work with my $who magic. Is there an alternative way of doing it?
I would like to avoid having different events because mine is triggered in the model:
class MyModel extends Model
{
use Notifiable;
protected $dispatchesEvents = [
'saved' => ModelUpdated::class,
'updated' => ModelUpdated::class,
];
}
As far as I know broadcastWith does not accept any parameter, Laravel 8.x.
You need to pass all your data through the constructor, then, make decision on what you need to return as event's payload.
Make sure to return an array from the broadcastWith() method.

Why is my Laravel Lumen listener being called twice?

My listener is being called twice, but the event is fired only once.
I got the code from Lumen 5.7 example and have no idea where is my mistake.
bootstrap/app.php
$app->register(App\Providers\EventServiceProvider::class);
app/Providers/EventServiceProvider.php
protected $listen = [
'App\Events\NewAuthEvent' => [
'App\Listeners\SendNewAuthListener',
],
];
app/Events/NewAuthEvent.php
use Illuminate\Queue\SerializesModels;
use App\Data\Entity\User;
use App\Data\Entity\Authorization;
use Illuminate\Support\Facades\Log;
class NewAuthEvent
{
use SerializesModels;
public $user;
public $auth;
public function __construct(User $user, Authorization $auth)
{
Log::debug("once :)");
$this->user = $user;
$this->auth = $auth;
}
}
app/Listeners/SendNewAuthListener.php
use App\Events\NewAuthEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Data\Service\MessengerService;
use Illuminate\Support\Facades\Log;
class SendNewAuthListener
{
private $messenger;
public function __construct(MessengerService $messenger)
{
Log::debug("twice :(");
$this->messenger = $messenger;
}
public function handle(NewAuthEvent $event)
{
Log::debug("twice as well :(");
$this->messenger->new($event->user, $event->auth);
}
}
firing the event:
event(new NewAuthEvent($objUser, $objAuthorization));
What am I missing? Is there some other parameter or config to be seted?
Thanks in advance!
I had the same issue. Check your EventsServiceProvider. If your are using a shouldDiscoverEvents method that returns true, removing it may solve your issue. See comment by andnacho here.

Why is martyshka/ShoppingCart ZF2 component not working (hidrator issue maybe)?

I'm having a lot of headache trying to implement martyshka/ShoppingCart component. All I found was the hydrator was null while adding items, but it didn't work too when I forced it (setting it on the component).
Here's my controller
<?php
namespace Publico\Controller;
use Doctrine\ORM\EntityManager;
use ShoppingCart\Controller\Plugin\ShoppingCart;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class CarrinhoController extends AbstractActionController
{
private $carrinho;
private $entityManager;
protected function setCarrinho(ShoppingCart $cart)
{
$this->carrinho = $cart;
return $this;
}
protected function getCarrinho()
{
if (null === $this->carrinho) {
$this->setCarrinho(new ShoppingCart());
}
return $this->carrinho;
}
/*...*/
public function indexAction()
{
try {
$carrinho = $this->getCarrinho();
} catch (\Exception $e) {
die($e->getMessage());
}
$carrinhoItems = [
'carrinho' => $carrinho->cart(),
'valorTotal' => $carrinho->total_sum(),
'qtdTotal' => $carrinho->total_items(),
];
die($carrinhoItems);
return new ViewModel([
'carrinho' => $this->carrinho->cart(),
'valorTotal' => $this->carrinho->total_sum(),
'qtdTotal' => $this->carrinho->total_items(),
]);
}
/*...*/
}
Here's the component repo
this component provides a plugin "ShoppingCart" to use, you do not need to create object of ShoppingCart.
if you properly install this component as module,
just use it in your action-
$this->ShoppingCart()

Laravel 5.1 event fire

I'm firing event and passing object with array like this:
$event = new App\Events\SendMessage;
$event->msg = [ 'sender_id'=>'191',
'recepient_id'=>'190',
'text'=>'some text',
];
Event::fire($event);
Is it possible to make this call a bit shorter and fire event in one line like this?
Event::fire(new App\Events\SendMessage([
'sender_id'=>'191',
'recepient_id'=>'190',
'text'=>'some text',
]));
You would just need to make sure your event constructor is setup to populate that field.
See: http://laravel.com/docs/5.1/events#defining-events
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
class SendMessage extends Event
{
use SerializesModels;
public $msg;
public function __construct($msg)
{
$this->msg = $msg;
}
}
Yep. Just pass the data in the __construct()
class SendMessage extends Event
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
}
In your App\Events\SendMessage you need to define a constructor method for example:
namespace App\Events;
class SendMessage {
protected $data = null;
public function __construct(Array $data)
{
$this->data = $data;
}
}
you can fire event like this in laravel
just put the code into your controller
event(new App\Events\EventClassName());
if your Event has parameters then
event(new App\Events\EventClassName(['first' => 'value','second' => 'value']));

Mocking class parameter that returns a mock

I am new to unit testing and trying to test a controller method in Laravel 5.1 and Mockery.
I am trying to test a registerEmail method I wrote, below:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
use Mailchimp;
use Validator;
/**
* Class ApiController
* #package App\Http\Controllers
*/
class ApiController extends Controller
{
protected $mailchimpListId = null;
protected $mailchimp = null;
public function __construct(Mailchimp $mailchimp)
{
$this->mailchimp = $mailchimp;
$this->mailchimpListId = env('MAILCHIMP_LIST_ID');
}
/**
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function registerEmail(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
]);
$email = $request->get('email');
try {
$subscribed = $this->mailchimp->lists->subscribe($this->mailchimpListId, [ 'email' => $email ]);
//var_dump($subscribed);
} catch (\Mailchimp_List_AlreadySubscribed $e) {
return Response::json([ 'mailchimpListAlreadySubscribed' => $e->getMessage() ], 422);
} catch (\Mailchimp_Error $e) {
return Response::json([ 'mailchimpError' => $e->getMessage() ], 422);
}
return Response::json([ 'success' => true ]);
}
}
I am attempting to mock the Mailchimp object to work in this situation.
So far, my test looks as follows:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomeRouteTest extends TestCase
{
use WithoutMiddleware;
public function testMailchimpReturnsDuplicate() {
$listMock = Mockery::mock('Mailchimp_Lists')
->shouldReceive('subscribe')
->once()
->andThrow(\Mailchimp_List_AlreadySubscribed::class);
$mailchimp = Mockery::mock('Mailchimp')->lists = $listMock;
$this->post('/api/register-email', ['email'=>'duplicate#email.com'])->assertJson(
'{"mailchimpListAlreadySubscribed": "duplicate#email.com is already subscribed to the list."}'
);
}
}
I have phpUnit returning a failed test.
HomeRouteTest::testMailchimpReturnsDuplicate
Mockery\Exception\InvalidCountException: Method subscribe() from Mockery_0_Mailchimp_Lists should be called exactly 1 times but called 0 times.
Also, if I assert the status code is 422, phpUnit reports it is receiving a status code 200.
It works fine when I test it manually, but I imagine I am overlooking something fairly easy.
I managed to solve it myself. I eventually moved the subscribe into a seperate Job class, and was able to test that be redefining the Mailchimp class in the test file.
class Mailchimp {
public $lists;
public function __construct($lists) {
$this->lists = $lists;
}
}
class Mailchimp_List_AlreadySubscribed extends Exception {}
And one test
public function testSubscribeToMailchimp() {
// create job
$subscriber = factory(App\Models\Subscriber::class)->create();
$job = new App\Jobs\SubscribeToList($subscriber);
// set up Mailchimp mock
$lists = Mockery::mock()
->shouldReceive('subscribe')
->once()
->andReturn(true)
->getMock();
$mailchimp = new Mailchimp($lists);
// handle job
$job->handle($mailchimp);
// subscriber should be marked subscribed
$this->assertTrue($subscriber->subscribed);
}
Mockery will expect the class being passed in to the controller be a mock object as you can see here in their docs:
class Temperature
{
public function __construct($service)
{
$this->_service = $service;
}
}
Unit Test
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
In laravel IoC it autoloads the classes and injects them, but since its not autoloading Mailchimp_Lists class it won't be a mock object. Mailchimp is requiring the class atop it's main class require_once 'Mailchimp/Lists.php';
Then Mailchimp is then loading the class automatically in the constructor
$this->lists = new Mailchimp_Lists($this);
I don't think you'll be able to mock that class very easily out of the box. Since there isn't away to pass in the mock object to Mailchimp class and have it replace the instance of the real Mailchimp_Lists
I see you are trying to overwrite the lists member variable with a new Mock before you call the controller. Are you certain that the lists object is being replaced with you mocked one? Try seeing what the classes are in the controller when it gets loaded and see if it is in fact getting overridden.

Categories