How to make a class class be dispached on laravel? - php

I've a custom class to hold data and I want to dispatch it into a job, but every time that I try i got this error:
Object of class App\Gateways\Partner\Entities\PartnerData could not be converted to string
The class:
class PartnerData
{
public string $name;
public string $phone;
public function __construct($info)
{
$this->name = $info['name'];
$this->phone = $info['phone'];
}
}
The job class:
class MyJob implements ShouldQueue {
// traits imported...
private PartnerData $partner;
public function __construct(PartnerData $partner)
{
$this->partner = $parner;
}
public function handle()
{
// Process partner data
}
}
The code:
collect($datas)
->mapInto(PartnerData::class)
->each(fn(PartnerData $pd) => MyJob::dispatch($pd));
There's a similar question without a awnser here: Laravel Queue not able to convert class object to string how can i dispatch that?
How can I make the class PartnerData dispatchable/stringable ?

Seems like you want to dispatch an array of jobs by using each method to dispatch each of them. Alternatively, maybe you can use Bus::batch() to dispatch an array of jobs.
for example:
$jobArray = $this->createJobsArray($someValue);
Bus::batch($jobArray)->onQueue('selected-queue')->dispatch();

Related

Phpunit - How add another object type to mocking object

I need to add Mailable type to my mocked ActivationMail. Maybe you have better idea to mock my ActivationMail class?
Tested class:
class MailService
{
public function sendActivationEmail(User $user): void
{
$this->sendEmail(new ActivationMail($user));
}
//content
protected function sendEmail(Mailable $mailable): void
{
//content
}
}
ActivationMail:
class ActivationMail extends Mailable{}
Do you have idea how can I test it?
My test:
public function test_sendActivationEmail()
{
$user = Mockery::mock(User::class);
$mailable = Mockery::mock(Mailable::class);
Mockery::mock('overload:App\Mail\ActivationMail');
$mailService = new MailService();
$mailService->sendActivationEmail($user);
}
And my error:
TypeError: Argument 1 passed to App\Services\MailService::sendEmail()
must be an instance of Illuminate\Mail\Mailable, instance of
App\Mail\ActivationMail given

What is the differece between private and protected in OOP?

I don't understand what is the different between private method and protected method in Object Oriented PHP. After make a method private , I'm able to access it from extends class. Please check the code below -
<?php
class person{
private function namedilam(){
return "likhlam";
}
public function kicu(){
return $this->namedilam();
}
}
class second extends person{
}
$info = new second;
echo $info->kicu();
The difference will become clear when you do it like this:
class Liam {
private getFirstName() {
return "Liam";
}
public function getName() {
return $this->getFirstName();
}
}
class Max extends Liam {
private function getFirstName() {
return "Max";
}
}
class Peter extends Liam {
public function getLiamsName() {
return $this->getFirstName();
}
}
$max = new Max();
echo $max->getName();
// returns "Liam", not "Max" as you might expect
$peter = new Peter();
echo $peter->getLiamsName();
// PHP Fatal error: Uncaught Error: Call to private method Liam::getFirstName() [...]
Max will return "Liam" because the getName() calls getFirstName() in the Liam class, not the one from the class extending it. This means with private methods you can make sure that whenever in your class you call this method exactly this one is used and it will never be overwritten.
To explain it in general terms:
private methods are only accessible inside the class. They can not be overwritten or accessed from outside or even classes extending it.
protected methods are accessible inside the class and in extending classes, but you can't call them from outside like:
$max = new Max();
$max->iAmProtected();
This will neither work with private or protected methods.

Redefining PHP class functions on the fly?

I am trying to figure out how to import a large number of PHP class functions on the fly. For example...
class Entity
{
public function __construct($type)
{
require_once $type."_functions.php"
}
// ...
}
$person = new Entity("human");
$person->sayhi();
$cow = new Entity("cow");
$cow->sayhi();
human_functions.php:
class Entity redefines Entity
{
public function sayhi()
{
echo "Hello world!";
}
}
cow_functions.php:
class Entity redefines Entity
{
public function sayhi()
{
echo "Moo!";
}
}
I have found a few possibilities like classkit_method_redefine() and runkit_method_redefine() (which are "experimental", and they cannot modify the currently running class anyway). I am on PHP 5.3.3 right now, so I can't use Traits (Not sure if that is what I am looking for anyways). I have had success redefining the handler variable like this:
// Example 2:
class OtherEntity { /* Code Here */ }
class Entity
{
public function __construct($type)
{
global $foo;
unset($foo);
$foo = new OtherEntity();
}
}
$foo = new Entity();
But, this feels like a very hacky method. More importantly, if I don't name every instance of the class $foo, then it will not work. Are there any workarounds for what I am trying to do?
Note: I am aware that I can extend a class, but in my case when the Entity class is initiated, there is no safe way to know in advance what subclass it would need to be initiated with. Perhaps there is a method I could write, such as:
public function changeClass
{
this->class = OtherEntity;
}
Thanks for your help!
Here's an idea of a possible solution you could try. Let the Cow and Human classes extend the Entity class. However, the Entity class would use a factory to instantiate the objects based on if the value was safe. Let's look at this in more detail:
/*
* Class Entity should not be able to be instantiated.
* It should contain a factory to instantiate the
* appropriate entity and an abstract function declaring
* the method that each entity will need to implement.
*/
abstract class Entity {
public static function factory($type) {
return (is_subclass_of($type, "Entity")) ? new $type() : FALSE;
}
abstract public function sayHi();
}
/*
* Human class extends Entity and implements the
* abstract method from Entity.
*/
class Human extends Entity {
public function sayHi() {
echo "Hello World!";
}
}
/*
* Cow class extends Entity and implements the
* abstract method from Entity.
*/
class Cow extends Entity {
public function sayHi() {
echo "Moo!";
}
}
Now to use this method, call the factory method and if all works well, it'll instantiate the proper class which will extend Entity.
$person = Entity::factory("Human");
$person->sayHi();
$cow = Entity::factory("Cow");
$cow->sayHi();
Using, is_subclass_of() will keep you safe because if the passed in value is not a class that extends Entity, you'll be returned a value of FALSE.
If you'd like to see the above code in action, copy the above php code and test it out on phpfiddle.org.
One thing you can do is create Human and Cow as subclasses of Entity. When you do new Entity("Human"), you can store a newly created Human object inside the Entity instance.
Then you can use __call to redirect method calls to the "child element".
class Entity{
private $child;
public function __construct($type){
$this->child = new $type;
}
public function __call($func, $params=array()){
$method = method_exists($this, $func)
? [$this, $func] : [$this->child, $func];
return call_user_func_array($method, $params);
}
}
class Human extends Entity{
public function __construct(){}
public function sayhi(){
echo "Hello world!";
}
}
class Cow extends Entity{
public function __construct(){}
public function sayhi(){
echo "Moo!";
}
}
$person = new Entity("Human");
$person->sayhi();
$cow = new Entity("Cow");
$cow->sayhi();
The only downside is that $person and $cow are both Entity objects.

PHP Unit: Create common object to work with

I'm writing PHP Unit tests for a class, which make some curl requests. At the moment every test starts with my class instance initiation and login directive and ends with logout directive, e.g.
public function testSomeMethod(){
$a = new myClass();
$a->login();
....
$a->logout();
$this->assertTrue($smth);
I want to create one common object $a = new myClass(), call login method before all test and logout method after all tests. How can I do that?
In accordion with the PHPUnit documentation here you can use the following hook method:
The setUp() and tearDown() template methods are run once for each test
method (and on fresh instances) of the test case class.
Also
In addition, the setUpBeforeClass() and tearDownAfterClass() template
methods are called before the first test of the test case class is run
and after the last test of the test case class is run, respectively.
In your case you can define the login class as class member and instantiate (login) in the setUpBeforeClass() method and do the logout in the tearDownAfterClass()
EDIT: EXAMPLE
Consider the following class:
namespace Acme\DemoBundle\Service;
class MyService {
public function login()
{
echo 'login called'.PHP_EOL;
}
public function logout()
{
echo 'logout called'.PHP_EOL;
}
public function doService($name)
{
echo $name.PHP_EOL;
return $name;
}
}
This test case:
use Acme\DemoBundle\Service\MyService;
class MyServiceTest extends \PHPUnit_Framework_TestCase {
/**
* #var \Acme\DemoBundle\Service\MyService
*/
protected static $client;
public static function setUpBeforeClass()
{
self::$client = new MyService();
self::$client->login();
}
public function testSomeMethod1()
{
$value = self::$client->doService("test1");
$this->assertEquals("test1",$value);
}
public function testSomeMethod2()
{
$value = self::$client->doService("test2");
$this->assertEquals("test2",$value);
}
public static function tearDownAfterClass()
{
self::$client->logout();
}
}
Dump the following output:
login called .test1 .test2 logout called
Time: 49 ms, Memory: 6.00Mb
OK (2 tests, 2 assertions)
hope this help
Creating reusable / common object at class level ( to be use in methods/functions) answer by #Matteo was helpful, Here is my implementation
no need for multiple inheritance , or __construct() constructor, I spent a lot of time on that ( specially coming from java background)
<?php
namespace Tests\Unit;
use Tests\TestCase;
use App\Services\HelperService;
class HelperServiceTest extends TestCase
{
//Object that will be reused in function()'s of this HelperServiceTest class itself
protected static $HelperServiceObj;
//this is the magic function
public static function setUpBeforeClass()
{
self::$HelperServiceObj = new HelperService();
}
public function testOneHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValue());
}
public function testTwoHelperServiceToBeTrue()
{
$this->assertTrue(self::$HelperServiceObj->getValueTwo());
}
}
Refer official docs setUp() , setUpBeforeClass() , tearDown() for magic function like setUpBeforeClass()
Sample implementation of getValue() function in HelperServiceTest class
<?php
namespace App\Services;
class HelperServiceTest
{
function getValue(){
return true;
}
function getValueTwo(){
return true;
}
}

Callback passed in class variables are empty on var_dump

I have a class that is similar to this striped down version:
abstract class MainClass extends Thread{
protected $events = [];
public function on($message, callable $callback){
$this->events[$message] = $callback;
}
}
class MyClass extends MainClass{
// has some random methods
}
I then run this which creates an instance of the class, it then runs a callback which runs the method in the passed in class.
$myClass = new MyClass();
call_user_func_array("myCallback", array($myClass));
var_dump($myClass);
function myCallback($class){
$class->on("message", function(){
// Do some stuff
});
}
When I do the var_dump on the class, the MyClass::$var array is empty. Why is that?
Edit
If I don't extend the Thread class, this works. Why is the Thread class not allowing me to edit my properties?
I was able to get this to work by using a Stackable object. What I found out, is that arrays are not thread safe, so to accomplish the task I did this:
class Events extends Stackable{
public function add($message, callable $callback){
$this[$message] = $callback;
}
}
abstract class MainClass extends Thread{
protected $events;
public function __construct(Events $events){
$this->events = $events;
}
public function on($message, callable $callback){
$this->events->add($message, $callback);
}
}
class MyClass extends MainClass{
// has some random methods
}
$evts = new Events();
$myClass = new MyClass($evts);
call_user_func_array("myCallback", array($myClass));
var_dump($myClass);
function myCallback($class){
$class->on("My Message", function(){
// Do some stuff
});
}

Categories