Adding a custom faker service provider? - laravel

I'm trying to add https://github.com/morawskim/faker-images to faker in Laravel.
I have a faker service provider...
<?php
namespace App\Providers;
use Faker\{Factory, Generator};
use Illuminate\Support\ServiceProvider;
class FakerServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register()
{
$this->app->singleton(Generator::class, function () {
$faker = Factory::create();
$faker->addProvider(new \Mmo\Faker\PicsumProvider($faker));
$faker->addProvider(new \Mmo\Faker\LoremSpaceProvider($faker));
$faker->addProvider(new \Mmo\Faker\LoremFacesProvider($faker));
return $faker;
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
This is conditionally loaded via the app service provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
if (!$this->app->environment('production')) {
$this->app->register('App\Providers\FakerServiceProvider');
}
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
}
Yet, fake()->picsumUrl() gives the error Unknown format "picsumUrl".
I've checked and the faker service provider is ran. There is no issues with the package either as I can do the following and get an image url...
$faker = \Faker\Factory::create('en_GB');
$faker->addProvider(new \Mmo\Faker\LoremFacesProvider($faker));
dd($faker->loremFacesUrl(1234));
So there must be something wrong with how the package is being added to faker.

Related

How can i use the Queue::after on Laravel?

I'm using Queue to send my mails on my application, and it's working great:
class SendMail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $user_mail;
private $person_data;
private $title;
private $company_name;
private $html;
private $email_sender;
private $email_reply;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($user_mail, $person_data, $title, $company_name, $html, $email_sender, $email_reply)
{
$this->user_mail = $user_mail;
$this->person_data = $person_data;
$this->title = $title;
$this->company_name = $company_name;
$this->html = $html;
$this->email_sender = $email_sender;
$this->email_reply = $email_reply;
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
Mail::to($this->user_mail)
->queue(new DocumentMessage($this->person_data, $this->title, $this->company_name, $this->html,
$this->email_sender, $this->email_reply));
}
}
Now I want to get the log of the moment when the emails were sent by the queue and, following the documentation, I put this code in my AppServiceProvider for testing:
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Carbon::setLocale('pt_BR');
setlocale(LC_ALL, 'pt_BR');
Carbon::setUtf8(true);
Paginator::useBootstrapThree();
Blade::withoutDoubleEncoding();
Queue::after(function (JobProcessing $event) {
DB::raw("INSERT INTO activity_log (log_name, description, subject_id, subject_type, causer_id, causer_type, properties)
VALUES ('email_sent', now(), null, null, 1111,
'App\Models\User','');");
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
But nothing happens after i send mails using my queue. Should i restart my queue job or do something after modify AppServideProvider?
According to the documentation, JobProcessed is the right event class to use. You might want to update this:
Queue::after(function (JobProcessed $event) {
...
});
By the way, I suggest a bit cleaner approach that leverage the framework better. Laravel has already includes the Illuminate\Mail\Events\MessageSent out of the box. So you can listen to the mail event.

Can not get Request data in custom service?

I have custom service:
<?php
namespace App\Library\Services;
use Illuminate\Http\Request;
class RegisterCustomerService
{
private $request;
public function constructor(Request $request)
{
$this->request = $request;
}
public function register($role)
{
dd($this->request);
}
}
Why I can not get dd($this->request); when I do POST request:
$customer = $registerCustomerService->register('customer');
My service provider is:
class RegisterCustomerServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* #return void
*/
public function register(Request $request)
{
$this->app->bind('App\Library\Services\RegisterCustomerService', function ($app) {
return new RegisterCustomerService($request);
});
}
/**
* Bootstrap services.
*
* #return void
*/
public function boot()
{
//
}
}
You don't need to bind the instance in the container because Laravel can automatically resolve the namespace and the class dependencies if you resolve an object through the container.
You can the remove the binding from the service provider and use:
$customer = app('App\\Library\\Services\\RegisterCustomerService')->register('customer');
In this way the container will resolve the Register customer service and will create that with all the needed dependencies (the request object in your example).

How can I create a controller constructor in Laravel that takes in two concrete implementations of the same interface?

Background
Note: this is using Laravel 5.3, Please don't judge.
We are trying to use dependency injection with our laravel controllers and push as much business logic into repos that are injected to controllers upon the controller instantiation.
We already have this functioning example:
class AcmeController extends Controller
{
protected $repository;
public function __construct(AcmeInterface $repository)
{
$this->repository = $repository;
}
}
inside app/Providers/RepositoryServiceProvider.php we do the binding:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\AcmeInterface::class, \App\Repositories\OpCity\AcmeRepo::class);
}
}
and then the AcmeRepo naturally implements the AcmeInterface:
class AcmeRepo implements AcmeInterface
Question
right now we have a case where some of the data of the same model is persisted in a memory type storage (redis) and the rest is persisted in relational db storage (psql). We would like to have two separate repos where each repo is specific to its storage type, ie RedisAcmeRepo and SqlAcmeRepo
How is it possible to do this in the AcmeController constructor?
public function __construct(AcmeInterface $sqlRepo, AcmeInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
For example you may do this:
$this->app->bind(AcmeController::class, function ($app) {
return new AcmeController($app->make(sqlRepo::class), $app->make(redisRepo::class));
});
Or this:
$this->app->when(AcmeController::class)
->needs('$sqlRepo')
->give($app->make(sqlRepo::class));
$this->app->when(AcmeController::class)
->needs('$redisRepo')
->give($app->make(redisRepo::class));
based on the answers above I came up with this solution, that kind of uses the composite pattern as well (I changed the name of the repos from Acme to ShopperLogs):
<?php
interface ShopperLogInterface
{
public function getLogs($from, $to, $shopper);
}
class ShopperLogsController extends Controller
{
/**
* service
*
* #var \App\Repositories\Contracts\ShopperLogInterface
* #access protected
*/
protected $manager;
public function __construct(ShopperLogInterface $manager)
{
$this->manager = $manager;
}
}
class ShopperLogManager implements ShopperLogInterface
{
protected $sqlRepo;
protected $redisRepo;
public function __construct(ShopperLogInterface $sqlRepo, ShopperLogInterface $redisRepo)
{
$this->sqlRepo = $sqlRepo;
$this->redisRepo = $redisRepo;
}
public function getLogs($from, $to, $shopper)
{
$todayRange = //get the today part of from -- to
/**
* array of ShopperLogs
*/
$todaysLogs;
if ($todayRange) {
$this->redisRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
$legacyRange = //get the part of from -- to that excludes today's range
/**
* array of ShopperLogs
*/
$legacyLogs;
if ($legacyLogs) {
$this->sqlRepo->getLogs($todayRange->start, $todayRange->finish, $shopper);
}
return merge($todayRange, $legacyRange);
}
}
class ShopperLogsSqlRepo implements ShopperLogInterface
{
/**
* #var /Illuminate\Database\Eloquent\Model/ShopperLogs
*/
protected $model;
/**
* #param /Illuminate\Database\Eloquent\Model/ShopperLogs $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do eloquent sql stuff here
}
}
class ShopperLogsRedisRepo implements ShopperLogInterface
{
/**
* #var \Redis\Model\Class
*/
protected $model;
/**
* #param \Redis\Model\Class $model
*/
public function __construct(ShopperLogs $model)
{
$this->model = $model;
}
public function getLogs($from, $to, $shopper)
{
$this->model->whereLogs //do redis stuff
}
}
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class RepositoryServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, \App\Managers\ShopperLogManager::class);
$this->app->bind(ShopperLogsController::class, function ($app) {
return new ShopperLogsController($app->make(ShopperLogManager::class));
});
$this->app->bind(\App\Repositories\Contracts\ShopperLogInterface::class, function() {
return new \App\Managers\ShopperLogManager(new \App\Repositories\ShopperLogsSqlRepo(new \App\ShopperLog), new \App\Repositories\ShopperLogsRedisRepo(new \App\ShopperLog));
});
}
}

Can an Eloquent model has multiple Observer?

Hi I want write a trait to add an observer to model but I thought write boot method is not the right way and finnaly i find that i can boot trait like boot[TraitName] but i wonder if i add an observer with code like this:
trait CreateObserver
{
public static function bootCreateObserver()
{
static::creating(function (Model $model) {
// ...
});
}
}
can I add another observer for my model like below or it will overriding my trait observer?
class MyModel extends Model
{
use CreateObserver;
public static function boot()
{
static::creating(function ($model) {
// ...
});
}
...
}
That's not the right way. I think this might help you:
https://laravel.com/docs/5.6/eloquent#observers
You bind observers to your models using a service boot:
<?php
namespace App\Providers;
use App\User;
use App\Observers\UserObserver;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
User::observe(UserObserver::class);
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
//
}
}
Inside the observer you can add all desired functionality:
<?php
namespace App\Observers;
use App\User;
class UserObserver
{
/**
* Listen to the User created event.
*
* #param \App\User $user
* #return void
*/
public function created(User $user)
{
//
}
/**
* Listen to the User deleting event.
*
* #param \App\User $user
* #return void
*/
public function deleting(User $user)
{
//
}
}
And to elaborate. Yes it can have multiple observers. Although I never seen a useful situation for that:
public function boot()
{
User::observe(UserObserver::class);
User::observe(AuthenticableModelsObserver::class);
}
This way both the UserObserver() and AuthenticableModelsObserver() are binded to the User() model on boot.

Event listeners not firing in Laravel 5.1

I am having an issue getting my event listeners to fire in Laravel 5.1.
I am firing the following event:
/**
* Add new project.
*
* #param AddNewProjectRequest $request
* #return Redirect
*/
public function add(AddNewProjectRequest $request)
{
// Event(s);
Event::fire(new ProjectAdded($project, $request->only('file')));
}
I have the following event setup:
<?php
namespace App\Events\Project;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class ProjectAdded extends Event
{
use SerializesModels;
public $project;
/**
* Create a new event instance.
*
* #return void
*/
public function __construct($project)
{
$this->project = $project;
}
/**
* Get the channels the event should be broadcast on.
*
* #return array
*/
public function broadcastOn()
{
return [];
}
}
Here is my EventServiceProvider file:
<?php
namespace App\Providers;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
\App\Events\ProjectAdded::class => [
\App\Listeners\Project\ImportFileListener::class,
],
];
/**
* Register any other events for your application.
*
* #param \Illuminate\Contracts\Events\Dispatcher $events
* #return void
*/
public function boot(DispatcherContract $events)
{
parent::boot($events);
//
}
}
Here is my ImportFileListener listener:
<?php
namespace Woodford\Listeners\Project;
use Woodford\Events\ProjectAdded;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
class ImportFileListener
{
/**
* Create the event listener.
*
* #return void
*/
public function __construct()
{
}
/**
* Handle the event.
*
* #param ProjectAdded $event
* #return void
*/
public function handle(ProjectAdded $event)
{
dd('listener');
}
}
As you can see above I have added dd('listener'); to see if the listener gets fired - it doesn't!
I have also tried running php artisan optimize and composer dump-autoload but still no luck!
Does anyone know what could be wrong?

Resources