I'm trying to reuse a Job code for handling two different tasks with same methods (MyClass1 and MyClass2). I've write an abstract class for passing it to the Job handler, however I get the message 'is not instantiable'.
This is what I'm trying to do
abstract class MyAbstractClass
{
abstract public function doSomething();
}
class MyClass1 extends MyAbstractClass
{
public function doSomething(){
// do some staff
}
}
class MyClass2 extends MyAbstractClass
{
public function doSomething(){
// do some staff
}
}
class MyJob extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
public function __construct()
{
}
public function handle(MyAbstractClass $myObj)
{
$myObj->doSomething();
// it executes the method doSomething of MyClass1 or MyClass2 depending on the enqueued Job
}
}
Any solution? If not, I will do two Jobs, one for each class... what do you think?
Thank you
Related
I have a Laravel project where I have created an abstract class that several of my jobs will use as they all need to use the same method to find some data to proceed.
In Laravel, the way jobs work is that the constructor takes any values that you trigger the job with and in a handler method, dependencies can be injected, like so:
class SomeJob extends Job implements ShouldQueue
{
public function __construct(array $someData, int $someMoreData)
{
$this->someData = $someData;
$this->someMoreData = $someMoreData;
}
public function handle()
{
// Do something...
}
}
\Queue::pushOn(Queue::getDefaultQueue(), new SomeJob([1, 2, 3], 4));
This means that I cannot just pass dependencies into the abstract class from the extending class' constructor. The only way around it, that I can see, is to have a property on the abstract class and then set it in the handler method of the extended class.
abstract class SomeAbstractClass extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $configOne;
protected $configTwo;
protected $userRepository;
public function __construct()
{
$this->configOne = config('someConfig.valueOne');
$this->configTwo = config('someConfig.valueTwo');
}
public function doSomethingWithUserRepository()
{
return $this->userRepository->doSomething();
}
}
class SomeClass extends SomeAbstractClass
{
public function __construct(array $someData, int $someMoreData)
{
parent::__construct();
$this->someData = $someData;
$this->someMoreData = $someMoreData;
}
public function handle(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
}
This works as intended, but it does not seem like the correct way to do it. It seems a bit hacky even if it works. Is there a way to get around this? This must he a pretty common problem, also outside of Laravel.
Because the defined constructor is used to deliver data in the jobs in Laravel, so in this case, you have to treat handle() as the "constructor" method.
So consider this example:
<?php
abstract class SomeAbstractClass extends Job implements ShouldQueue
{
use InteractsWithQueue, SerializesModels;
protected $configOne;
protected $configTwo;
protected $userRepository;
public function __construct()
{
$this->configOne = config('someConfig.valueOne');
$this->configTwo = config('someConfig.valueTwo');
}
public function handle(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
protected function doSomethingWithUserRepository()
{
return $this->userRepository->doSomething();
}
}
class SomeClass extends SomeAbstractClass
{
public function __construct(array $someData, int $someMoreData)
{
parent::__construct();
$this->someData = $someData;
$this->someMoreData = $someMoreData;
}
public function handle(UserRepository $userRepository)
{
parent::handle($userRepository);
// you can do whatever you liiike
$this->doSomethingWithUserRepository();
}
}
I would like to know if this is possible in Object Oriented Programming in php. I have a controller
class BaseController extends Controller{
/**
* #Route("/sample", name="sample")
*/
public function postSampleAction(Request $request){
}
}
and I have a file called ProductEvent and PriceEvent
class ProductEvent extends BaseController{
public function checkEvent(){
echo "product event";
}
}
class PriceEvent extends BaseController{
public function checkEvent(){
echo "price event";
}
}
as you can see I extend the BaseController. What I want to happen is that I need to put the checkEvent() to the BaseController in postSampleActioin()
class BaseController extends Controller{
/**
* #Route("/sample", name="sample")
*/
public function postSampleAction(Request $request){
$this->checkEvent();
}
}
I don't know if this is a proper way. I want to test if that will echo the checkEvent() function.
Sorry my mistake. I forgot to add what framework do I used. I used symfony for this.
That means you want to make BaseController an incomplete, abstract class which requires to be inherited and the checkEvent method to be implemented there:
abstract class BaseController extends Controller {
public function postSampleAction(Request $request) {
$this->checkEvent();
}
abstract public function checkEvent();
}
You now cannot instantiate BaseController by itself, and any inheriting non-abstract class needs to implement checkEvent; that gives you the required type safety that allows you to depend on checkEvent in postSampleAction.
Given I have an abstract class:
abstract class User{
private function getNumber(){
return 'Get number';
}
}
With the child class
class UserComments extends User{
public function rows(){
return $this->getNumberOfRows();
}
}
Question:
Is there any way to call the getNumber function when I try to call getNumberOfRows method in child class, or when I call getNumberOfRows() in child class I want getNumber to be called instead
?
Due to PHP's Object inheritance you can directly call the specific method. However, in your example the getNumberOfRows() function is missing.
class UserComments extends User {
public function rows() {
return $this->getNumber();
}
}
You can do something like this
abstract class User{
private function getNumber(){
return 'Get number';
}
public function getNumberOfRows(){
return $this->getNumber();
}
}
With the child class
class UserComments extends User{
public function rows(){
return $this->getNumberOfRows(); //Defined in the parent class
}
}
Abstract methods cannot be private, abstract must be implemented by the class that derived it.
You can either use public, or if you do not want it to be visible outside, make it protected, as following:
abstract class User{
abstract protected function getNumber();
}
Once you do this, you can implement the getNumber method in User class:
class User {
protected function getNumber() {
// Do something
}
}
Update: Please note that protected methods are accessible by child classes, you can use "hierarchy":
abstract class User{
abstract protected function getNumber();
}
class UserComment extends User {
protected function comment() {
// Do something
}
protected function getNumber() {
return 3;
}
}
class Post extends UserComment {
public function myMethod() {
echo $this->getNumber();
}
}
Also you can use interfaces, just an example:
interface User {
public function getNumber();
}
class UserComment {
protected function myMethod() {
// Do something
}
}
class Post extends UserComment implements User {
final public function getNumber() {
return 3;
}
public function myMethod() {
echo $this->getNumber();
}
}
$post = new Post();
$post->myMethod();
Is it OK to use properties/methods from parent classes in trait methods?
This code works, but is it good practice?
class Child extends Base{
use ExampleTrait;
public function __construct(){
parent::__construct();
}
public function someMethod(){
traitMethod();
}
}
trait ExampleTrait{
protected function traitMethod(){
// Uses $this->model from Base class
$this->model->doSomething();
}
}
I don't think it's good practice.
Instead you could have a method to fetch your model object, and have that method as an abstract signature in you trait:
trait ExampleTrait {
abstract protected function _getModel();
protected function traitMethod() {
$this->_getModel()->doSomething();
}
}
class Base {
protected $_model;
protected function _getModel() {
return $this->_model;
}
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod();
}
}
Or pass your model as a parameter to your trait method:
trait ExampleTrait {
protected function traitMethod($model) {
$model->doSomething();
}
}
class Base {
protected $_model;
}
class Child extends Base {
use ExampleTrait;
public function someMethod() {
$this->traitMethod($this->_model);
}
}
Both of these approaches let you utilize your IDE's type hinting.
class ControllerBase
{
}
class postSmsController extends ControllerBase
{
}
class SmsSentController extends ControllerBase
{
}
How to extends CotrollerBase along with other controller in phalcon, I want to use the functions of postSmsController in SmsSentController, also want to use function of ControllerBase in both Controller classes. what should i do
You can extend one from another
// Base controller
class ControllerBase
{
public function one()
{
}
}
// Extending. Offers one() and two()
class postSmsController extends ControllerBase
{
public function two()
{
}
}
// Extending. Offers one() and two() and three()
class SmsSentController extends postSmsController
{
public function three()
{
}
}
// Offers only one()
class otherController extends ControllerBase
{
}