override return type in PHPDoc - phpdoc

I have a class Abc with method (body is not important):
/**
* #return SomeBaseClass
*/
function getAll() { ... }
In child class of Abc called AbcChild I'd like to redefine only type of returning class to see it properly in Netbeans. Can I do it without redefining method:
/**
* #return SomeClass
*/
function getAll() { return parent::getAll(); }

Try something like this:
/**
* #method SomeClass getAll()
*/
class AbcChild
{
// ....
}
More info about #method

No, because you need the child method code itself in order to have a child docblock to associate with it. If you have the docblock but not the method code, the docblock won't be tied to anything, and thus will have no effect. Most people dislike altering their code to accommodate docblock behavior, though it's never really bothered me to do so.
However, another option for you is to adjust the #return tag on the parent method, so that it lists all possible return types that you want to indicate the children could return. That makes me wonder, though... if you are not actually overriding the method itself, then how is the child class actually returning a different class than the parent? I can see ways to do this in my mind, involving class properties that contain the differing class objects, but they'd feel like code smells to me ;-)
If there is no method override code itself in the child, then I would choose to put all possible return types in the parent's #return.

Actually I think there is other way than full method override. You can change #return phpdoc block in the child interface which extends base interface. Let me explain with code what I mean:
interface EntityRepository
{
/**
* #return object
*/
public function get($id);
public function add($entity, $sync = false);
public function remove($entity, $sync = false);
// other methods common for custom repositories
}
interface ProjectRepository extends EntityRepository
{
/**
* #return Project
*/
public function get($id);
}
This is part of your domain. And now the concrete implementation taken from Symfony & Doctrine:
use Doctrine\ORM\EntityRepository;
use Model\Repository\EntityRepository as BaseEntityRepository;
abstract class DoctrineEntityRepository extends EntityRepository implements BaseEntityRepository
{
public function get($id)
{
$entity = $this->find($id);
if (!$entity) {
throw new EntityNotFoundException();
}
return $entity;
}
public function add($entity, $sync = false)
{
// method implementation
}
public function remove($entity, $sync = false)
{
// method implementation
}
}
use Model\Repository\ProjectRepository as BaseProjectRepository;
class ProjectRepository extends DoctrineEntityRepository implements BaseProjectRepository
{
public function specificQueryForProjects()
{
// method implementation
}
}
This way you dont have to override methods in child classes only because of code autocomplete. You just have to extend interfaces to let users of your API know that the return value changed.

Related

Customize a trait class with AliasLoader::getInstance()?

I have a core trait class. This is integrated into core controllers and various independent modules (nwidart).
How is it possible to add or override functionality to a trait class? Without adjusting the controllers where the traits are integrated?
The goal is to override an existing trait function and I've tried that with "AliasLoader" so far, unfortunately so far without success.
namespace Modules\MyModule\Providers;
class Main extends Provider
{
public function register()
{
$loader = AliasLoader::getInstance();
$loader->alias('App\Traits\Documents', 'Modules\MyModule\Overrides\Traits\Documents');
}
}
namespace Modules\MyModule\Overrides\Traits;
use App\Traits\Documents as TraitTest;
trait Documents
{
use TraitTest {
getNextDocumentNumber as getNextDocumentNumber;
}
public function getNextDocumentNumber()
{
return '123456789';
}
}
The core trait is then integrated into a core controller, for example, and this cannot be adjusted!
namespace App\Notifications\Docu;
use App\Traits\Documents;
class Docu extends Notification
{
use Documents;
/**
* Get the mail representation of the notification.
*
* #param mixed $notifiable
*/
public function toMail($notifiable): MailMessage
{
$message->title($this->getNextDocumentNumber($this->docu);
return $message;
}
}

How to use laravel repository pattern searchable array?

I am using laravel-repository pattern ,i have one api which is responsible for getting all users it's working fine ,if we are using that package by default search should support for that i set $fieldSearchable array in the repository class.
i hit an api like this localhost.com/api/lists?search=foo,it's not working can you please help me where did i mistake
UserController.php
public function __construct(UserRepositoryInterface $repository)
{
$this->repository = $repository;
}
public function getUsers(){
$data = $this->repository->show();
return response()->json(fractal($data, new UserTransformer()));
}
UserRepositoryInterface.php
interface UserRepositoryInterface extends RepositoryInterface
{
public function show();
}
UserRepository.php
<?php
namespace App\Repositories;
use Prettus\Repository\Eloquent\BaseRepository;
use Prettus\Repository\Criteria\RequestCriteria;
use App\User as AppUser;
use App\UserSection;
use App\Validators\UserValidator;
use Illuminate\Support\Facades\DB;
/**
* Class UserRepositoryEloquent.
*
* #package namespace App\Repositories;
*/
class UserRepository extends BaseRepository implements UserRepositoryInterface
{
protected $fieldSearchable = ['phone_number'];
/**
* Specify Model class name
*
* #return string
*/
public function model()
{
return AppUser::class;
}
/**
* Boot up the repository, pushing criteria
*/
public function boot()
{
$this->pushCriteria(app(RequestCriteria::class));
}
public function show(){
return $this->model()::get();
}
}
It maybe resolved by utilising pre-difined methods No need to write show() function logic because by default l5-Repository pattern contains some methods to get all the data all()or paginate().in your controller write like this in getUsers()
$data = $this->repository->all();
or
$data = $this->repository->paginate('25');
all() is for fetch all the data from DB and paginate($limit) is fetch the data per page based on the limit.
if you are using any one of the above mentioned method then automatically search functionality will work

Laravel responsibility in the classes

I have a project on Laravel and need to do refactoring. I've read about Service provider and Dependency injection and have some questions.
This is a short structure: user model, event model, favorite user model and etc. Also, there are controllers for all models. Every event has a creator and client (user relationship). In every class, I am injecting appropriate service: User Service, Event service, Favorite user service and etc.
Let's consider the example - I want to delete the user:
class UserController extends Controller
{
/**
* #var UserService $userService
*/
protected $userService;
/**
* UserController constructor.
* #param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
protected function delete(int $id)
{
$user = User::find($id);
if ($user) {
$this->userService->setUser($user);
$this->userService->delete();
}
}
Inside User service, I am processing user deleting - update the appropriate field. Also, I need to cancel all user events and delete favorite users.
My question is where should I do it? Should I inject event and favorite user service in UserController or in UserService? Or maybe there is a better way to do this action. Thx in advance
Seems like you have many actions depending on deleting user, so I would consider using Events and inside each listener handle the specifics of it.
class UserController extends Controller
{
/**
* #var UserService $userService
*/
protected $userService;
/**
* UserController constructor.
* #param UserService $userService
*/
public function __construct(UserService $userService)
{
$this->userService = $userService;
}
protected function delete(int $id)
{
if(!$this->userService->delete($id)) {
// return some error;
}
event(new UserWasRemoved($id));
// return success response
}
class DeleteUserService {
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function delete($id){
return $this->user->delete($id);
}
}
// app/Providers/EventServiceProvider
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
UserWasRemoved::class => [
CancelUserEvents::class,
RemoveUserFavorites::class,
// etc...
],
];
}
if deleting a user is much code, I will create DeleteUserService class which will contain all the code needed to delete a user and the effects of the delete.
class DeleteUserService {
public function __construct(int $userId)
{
$this->userId = $userId;
}
public function delete(){
$this->deleteUser();
$this->updateAppropriateFields(); // of course the name should be clearer
$this->deleteEvents();
$this->deleteFavoriteUser();
...
}
private function deleteUser(){...}
private function updateAppropriateFields(){...}
private function deleteEvents(){...}
private function deleteFavoriteUser(){...}
...
}
and in your controller either you inject the service or instantiate a new instance in the controller method
class UserController extends Controller
{
...
public function delete(int $id)
{
$user = User::findOrFail($id);
$deleteService = new DeleteUserService($user->id);
$deleteService->delete();
}
}
it's always a good idea to break your large function into one or more classes.
I suggest you abandon your approach to using services like this. Everything that you implement with services has already been implemented in Laravel, only even easier. You are now implementing more cumbersome logic on top of a simple, ready-made one.
For each object of your subject area (user, event, favorite user) add model class. Add in them the information of tables, the data from which belong to them - unless of course you use relational storage Eloquent Model Conventions. Here I have a question for you - does the favorite user entity need a separate class? If the User and the FavoriteUser have the same characteristics (that is, class members in the implementation), then there is no need to distribute them into different classes, and it is enough to add an additional isFavourite() (bool) attribute - in the class and in the table.
Implement the necessary methods in the controllers for each of your model classes as described in the documentation Defining Controllers. Depending on the type of the client part, the return of the response can be either JSON for the RESTful API, or a blade template with the transmitted data Views. Here, in the controller, you should implement a method to delete the model.
If you do not want the logic to be similar, that is, get rid of the similar methods all(), get(), post(), put(), delete() and others for UserController, for EventController, ... (with the exception of model classes - which will be different), then I advise you use the following architectural trick (this is optional, of course). Develop a universal layer - a class of a universal model, a class of a universal controller, a class of a universal model repository (if you use it in development). And in the controller, describe the common logic for all model classes, all(), get(), post(), put(), delete(). And then inherit each concrete class of the model from the universal, each concrete class of the controller from the universal - and so on. But!
In a concrete class of the model, it is necessary, for example, in an array, to list the attributes of the relational storage table, where you get the data from; it is also necessary to specify the name of the class in the variable - so that the controller can understand which class it should work with.
And in the controller in any way pass data about the model class - for example, using DependencyInjection Dependency Injection & Controllers.
With this approach, the classes of concrete controllers become thin, and the increase in code in them occurs only due to the redefinition of universal methods or the implementation of custom ones.
The advantage of this approach is also that there is no need to add routes of a similar structure. For example, a universal route will suffice for you
Route::get('{entity}/{id}', function ($entity, $id) {
$module = ucfirst($entity);
Route::get("{$entity}/{$id}", "{$module}Controller#get");
});
instead of many of the same type
Route::get('user/{id}', 'UserController#get');
Route::get('event/{id}', 'EventController#get');
and the like.

How to write a custom function in a model?

There is a model data:
class Order extends Model
{
}
How to write a custom method inside the Order class so that it can be called in constructor like this:
Order::myMethod()
Order->myMethod()
Where myMethod is:
public function myMethod() {
return DB::query(<SQL QUERY>);
}
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Rather create a custom function in Model, You can use traits to achieve the desired output.
Please follow either steps:-
https://medium.com/#kshitij206/traits-in-laravel-5db8beffbcc3
https://www.conetix.com.au/blog/simple-guide-using-traits-laravel-5
Guess you are asking about the static functions:
class Order extends Model {
public static function myMethod() {
}
}
and you can call it anywhere like
Order::myMethod();
You can achieve the desired behavior using magic methods __call and __callStatic
if your real method is static you can use __call() to intercept all "non static" calls and use it to call the static and use __callStatic to forward the calls to a new instance to that class .
Your methods should be always static because if a non static method exists and you are calling it statically php raises an error
Non-static method Foo::myMethod() should not be called statically
No problem if your method is static
class Order extends Model {
public static function myMethod() {
return static::query()->where(...)->get(); // example
}
public function __call($name, $arguments) {
return forward_static_call_array([__CLASS__, $name], $arguments);
}
public static function __callStatic($name, $arguments) {
return call_user_func_array([app(__CLASS__), $name], $arguments);
}
}
(new Order())->myMethod();
Order::myMethod();
I can't understand your exact problem is. but if you are using laravel, then you can write custom method inside the ABC model like this
class ABC extends Model
{
//here is your fillable array;
public function abc()
{
//Here is your Eloquent statement or SQL query;
}
}
just call this abc() method inside the controller like this
use ABC;
class AbcController extends Controller
{
private $_abc; // it is private variable
// this is constructor
public function __construct(ABC $abc)
{
$this->_abc= $abc;
}
public function abcMethod()
{
$this->_abc->abc();
}
}
Thanks
I don't believe I'm understanding your intention. You've stated:
Purpose is to move SQL queries inside model's class, that don't mess this code in controllers.
Why does the Order->myMethod() need calling inside the constructor? If you're trying to design your data access layer to work efficiently, you can use data repositories.

Javadoc for enum field method

I have an enum which implements an interface. The method is implemented in its constants with a comment for each method:
public interface MyIF{
int foo1();
}
public enum SomeTypes implements MyIF{
TYPE_ONE {
/**
* this method ...
*
* #return ...
*/
#Override
public int foo1() {...}
}, ...
}
Javadoc ignores the method comment. Everything else is generated fine. Is there a way I can make these comments appear in the generated javadoc ?
Thanks

Resources