I am using AntonioRiveiro/Tracker repo for my laravel app. I would like to add some more functionality to it that it doesn't have out of the box.
But I can't find where its instance gets created, or how to access the Tracker object in my Controllers.
Or how do I extend the tracker object?
So I think the easiest way for you to go about this is the following:
First, make your own ServiceProvider
php artisan make:provider CustomTrackerServiceProvider
Now open up that file, we'll need to make some modifications.
Firstly, we'll need to extend the ServiceProvider that Tracker provides.
use PragmaRX\Tracker\Vendor\Laravel\ServiceProvider as TrackerServiceProvider
class CustomTrackerServiceProvider extends TrackerServiceProvider
The use alias above is not required, but I prefer it for clarity given the similar naming convention to the core framework.
Now you'll need to replace your usage of the PragmaRX\Tracker\Vendor\Laravel\ServiceProvider in your config/app.php file under the providers array
config/app.php
'providers' => [
//other providers and what have you
App\Http\Providers\CustomTrackerServiceProvider::class
]
Now you have the ability to make changes. You can override the default functionality of the core class as long as it's member is not private.
Have a look at the vendor provided file and identify a similar architecture pattern to the vendor maintainer, and you'll be good to go.
The answer to this question provides a solution for (2), I found the answer to (1) here.
To access the tracker object you need to include:
use PragmaRX\Tracker\Vendor\Laravel\Facade as tracker;
Then you'll do something like:
$visitor = Tracker::currentSession();
as described in the documentation.
Related
In order to reduce some code duplication in my fixture classes, I would like to create a custom provider for Faker (fakerphp/faker) in my Symfony 5 application. Where can I create a custom faker provider in my application? Please note that I am new to developing in Symfony.
Related to this topic I have found this question for Laravel, but of course Symfony has a different project setup.
Reading up to the documentation of a related library, I would expect I could use $faker->addProvider(), but then again I do not know where this code should live in my Symfony application.
I fantasize I should make a Service for this functionality, or maybe I should just add it to my BaseFixture class? But these are just wild guesses for me.
Where you put your provider is a subjective question. Some use src/Test/ (or namespace App\Test) for test related code that is not actual tests. Others will place it next to the tests somewhere in the tests/ directory, e.g. tests/Faker/ (with namespace App\Tests\Faker). The benefit of the latter is, that the classes will only be picked up by autoload-dev and not in production.
Regarding the second part of your question, how to add the provider to Faker that depends on how you use it in your tests or more precisely, if you want to fetch a shared faker instance from your container or manually create one. Especially if your provide relies on other services like Doctrine you probably want to register it in the container or you should rethink your provider as relying on the database might cause issues, e.g. when you reset your test database, the data pool for your provider might be gone.
I would go for creating a faker instance in your tests as the cost of initiating Faker is relatively low, it should not noticeably slow down your tests if done multiple times, and you will be forced to avoid tying the provider to services from your production code accidentally. You will also have more control over how you create your faker instance and which providers you want to load for specific tests, if that is relevant for you. For instance you could create an instance in the setUp method of your tests:
class MyTest extends TestCase
{
private $faker;
protected function setUp(): void
{
// The Faker\Factory will create a ready to use Faker Generator
$this->faker = Factory::create();
$this->faker->addProvider(new MyCustomProvider());
}
public function testSomething(): void
{
$title = $this->faker->title;
}
}
The Factory will create a new Faker\Generator with all the default providers already registered. You can look at the code if you'd rather only have your own providers in there. Instead of copying this code in each test you can share it, e.g. by creating your own TestCase-class that your tests extend instead of the one provided by PHPUnit or you could use a trait. I think either approach is fine, but probably having your own base TestCase if you are not yet familiar with Traits.
With the setUp method above you can also look at how Symfony's Service Container works, especially how to create services through a factory and then, for example create a config/services_test.yaml where you create a faker instance that you can get in tests extending the WebTestCase or KernelTestCase after booting your Symfony kernel.
I would like to load a list of classes dynamically. The general idea would be to have a sort of manifest/config file that contains an array list of classes and then they would "automatically" be loaded into my application instead of needing to manually do something like
use App\Controllers\UserController;
use App\Controllers\ContractController;
use App\Controllers\SubscriptionController;
etc...
It seems there must be some way to achieve this as the Laravel framework does something similar with service providers. You register the classes once in config/app.php and then these provider classes are auto loaded onto the app.
If you are looking for a native/homemade solution without any PSR0/4 convention or composer package manager, you can consider use spl_autoload_register and __autoload to make your own logic to resolve the classes.
But i would strongly recommend composer and PSR4 standarts for this.
Here is the example of a customer resolver/loader class
https://www.php.net/manual/en/function.spl-autoload-register.php#102180
There are many questions regarding loading custom helper classes in Laravel. However, none of them focus on the loading them with proper initialization.
As of Laravel version 5.3 we can use psr-4 autoloading which is autoloading the entire app/ directory. However, classes are loading but never initialized.
I have my helper class inside the app/helpers/support.php. This class has a constructor, where I want to load some important configuration in order to make the helper usable.
So how can I load my helper but ALSO initialize it properly in Laravel? Right now I am simply working-around the problem by using new \App\Helper\Support(); inside AppServiceProvider.php.
Edit: I'm using the following approach to maintain my helper class:
Best practices for custom helpers on Laravel 5
It seems like what you have is a service. Rather than creating an instance, you can declare it in your app service provider and inject it as a dependency when you need it.
In your register method:
$this->app->bind(\App\Helper\Support::class);
You can now use dependency injection to get an instance of your class. You can also make an instance like this:
app()->make(\App\Helper\Support::class);
If you only want one instance to exist at any given time, use singleton rather than bind.
I recommend reading the service container documentation:
https://laravel.com/docs/5.5/container
Few days ago I started to learn Laravel and I can't understand one mechanism: there is AppServiceProvider where I can register (bind) my custom classes, interfaces, etc.. But in many tutorials when author creates custom classes for registration them they also creates custom service provider class instead of using "register" method in AppServiceProvider. And I cann't figure out, why they don't use AppServiceProvider?
Also, I looked at other builtin serviceproviders, and found there some methods and fields that are not described in official guide (for example, AuthServiceProvider has protected $policies field). Maybe, understanding this helps me to understand, where I can use standard provider and where custom? But I can't google any link answering this question.
Thank you for your answers.
Mostly it's all about readability of your code. You can probably just put everything in the AppServiceProvider and it will work, but over time, the file will be very long and very hard to orientate in so you might want to separate things and make custom ServiceProviders for each part of your application logic.
It really is up to you how you want to structure your files and folders. As for me, I try to make my files modular (separate a piece of functionality within it's own module, e.g. Authentication is a module). Grouping service providers that are related to this module will be in a separate service provider to avoid cluttering the AppServiceProvider.
I implemented a role/permission system. Now I want to add a method to Laravel router so I can make something like this:
Route::get('sales', 'SaleController#index')->allow('Salesman');
I know that I can use #can('Salesman') (View) and $user->can('Salesman') (Controller) but I found so much readable the way I'm trying to do it since I'll be able to see all role permission access in the routes file.
You can override the router class, then register it into service container to be used by Route facade.
To be more clear:
Write a class that extends Laravel's router (I think Router class). To find this, open the Route facade, then find its service provider. From there, it should be easy to find the router class.
Write a class that overwrites that router. Make sure to extend the class you found before.
Write a service provider that overwrites the router services. The practically means to register your service under the same key name you find in Route facade.
And that should be it. Your service is now picked by Route facade automatically.
As you're using the facade to generate the routes. This should be quite easy. The facade can be overruled in the config/app.php facades array.
You can generate your own Facade class and replace the native one with yours. Which in fact is a Router class. In order to implement the functionality you need to extend and override the following in sequence:
Facade
Router::newRoute
Route
By extending the last one and returning those in the newRoute method of the Router, you'll be able to overrule the logic of Laravel.