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

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;
}
}

Related

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: Issue with calling custom Facade

I'm using Laravel 8 and I'm creating a custom Facade, but I cannot recall it with LogActivity::log($payload) but only with LogActivityFacade::log($payload).
Cannot see where is my fault...
app\Helpers\LogActivityFacade.php
<?php
namespace App\Helpers;
use Illuminate\Support\Facades\Facade;
class LogActivityFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'logactivity';
}
}
app\Helpers\LogActivityHelper.php
<?php
namespace App\Helpers;
use App\Repositories\LogActivityRepository;
class LogActivityHelper
{
public function log($payload)
{
$repository = new LogActivityRepository();
$repository->store($payload);
}
}
app\Providers\LogActivityServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\Facades\App;
use App\Helpers\LogActivityHelper;
use Illuminate\Support\ServiceProvider;
class LogActivityServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->bind('logactivity', function() {
return new LogActivityHelper();
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
config/app.php
In providers array
[...]
App\Providers\LogActivityServiceProvider::class,
In alias array
'LogActivity' => App\Helpers\LogActivityFacade::class,
I tried also composer dump-autoload and php artisan config:clear, but I can access to the Facade (and it works...) only with LogActivityFacade::log() instead of LogActivity.
This is the expected behavior. Laravel doesn't create new classes for you it just proxies methods from the service class in the facade using the __call magic method. If you take a peek at, for example, the Auth or Route facade in the vendor directory you will see that they are named Auth and Route respectively not AuthFacade and RouteFacade. So just name your facade LogActivity. If you need to differentiate it from the service class you can use namespacing or just postfix the service class name with something as you have already done.
You can do this for easy access to the facades
namespace App\Facade;
use Illuminate\Support\Facades\Facade;
abstract class BaseFacade extends Facade
{
/**
* #return string
*/
public static function getFacadeAccessor()
{
return static::class ;
}
/**
* #param $class
*/
static function shouldProxyTo($class)
{
app()->singleton(self::getFacadeAccessor(),$class);
}
}
extend other facades
namespace App\Facade\Plugins;
use App\Facade\BaseFacade;
/**
* #method static convertPersianNumberToEnglish($number)
* #method static bool checkDataIsTrue(array $results = [])
* #method static string|null removeFileTypeName(string $string = null)
*/
class GlobalPluginsFacade extends BaseFacade
{
}
register in services provider
public function boot()
{
// global facades
GlobalPluginsFacade::shouldProxyTo(GlobalPluginsRepo::class);
}
And easy to use.
GlobalPluginsFacade::getFunction();

Why Repository interface bind to service container

We need to use Repository in laravel application. We want create Two important things one is Repository Interface and another one Repository class
My doubt is Why Repository interface and Repository class register to service provider
I removed repository interface and class from service provider
show below error
"Target [App\Repository\UserInterface] is not instantiable while building "
<?php
namespace App\Repository\user;
use Illuminate\Support\ServiceProvider;
class UserRepoServiceProvide extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
// $this->app->bind('App\Repository\UserInterface', 'App\Repository\user\UserRepository');
}
}
An Interface class is just a definition of methods (without their body), hence is not instantiable. That means you can't do a new App\Repository\UserInterface().
Somewhere in your code you have a method (or maybe a constructor?) that takes a UserInterface dependency, something like
public function myMethod(UserInterface $repository) {
...
}
// or
public function __construct(UserInterface $repository) {
...
}
If you remove the binding, Laravel will try to instantiate an UserInterface and that will result in the error you get.
When working with interfaces you have always to bind() them with concrete classes.
I have a question, why did you remove the binding from ServiceProvider?

override return type in 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.

Laravel 4 facade class not calling functions on facade root class

I've set up a package in laravel 4 via the artisan workbench command. I created a facade class and followed this tutorial to come up with the following service provider, facade and root classes:
src/Spoolphiz/Infusionsoft/InfusionsoftServiceProvider.php:
namespace Spoolphiz\Infusionsoft;
use Illuminate\Support\ServiceProvider;
class InfusionsoftServiceProvider extends ServiceProvider {
protected $defer = false;
/**
* Bootstrap the application events.
*
* #return void
*/
public function boot()
{
$this->package('spoolphiz/infusionsoft');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
// Register 'infusionsoft' instance container to our Infusionsoft object
$this->app['infusionsoft'] = $this->app->share(function($app)
{
return new Spoolphiz\Infusionsoft\Infusionsoft;
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return array();
}
}
src/Spoolphiz/Infusionsoft/Facades/Facade.php:
namespace Spoolphiz\Infusionsoft\Facades;
use Illuminate\Support\Facades\Facade;
class Infusionsoft extends Facade {
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor() { return 'infusionsoft'; }
}
Finally I've set up the underlying class thats to be connected to the facade at src/Spoolphiz/Infusionsoft/Infusionsoft.php:
namespace Spoolphiz\Infusionsoft;
//use Spoolphiz\Infusionsoft\iSDK;
/*
This is hackish and a un-laravel way to handle the requirement of \iSDK but unfortunately the xmlrpc3.0 lib doesn't want to correctly encode values when run with a namespace. Will try to resolve this later.
*/
require_once(__DIR__.'/isdk.php');
class Infusionsoft extends \iSDK {
protected $_app;
/**
* Init the sdk
*
*/
public function __construct( $connectionName )
{
$this->_app = parent::cfgCon($connectionName);
}
public function test()
{
dd('works');
}
}
I set up the service provider and the facade alias of Infusionsoft in app/config/config.php.
When I try running methods belonging to the extended iSDK class against an instance of Spoolphiz\Infusionsoft\Facade\Infusionsoft I get undefined method errors, such as the following:
Call to undefined method Spoolphiz\Infusionsoft\Facades\Infusionsoft::loadCon()
Why is this? The whole point of facades is to be able to call methods against its root class...
Looks like I was being stupid. I was developing this package in the laravel workbench. Once it was done I submitted it to packagist and set up a requirement for it in the same laravel app. Having the package installed in vendors directory and in the workbench caused some sort of conflict.
Lesson learned: make sure you dont have the same package in your workbench and in your application's vendors directory.

Resources