I develop the Laravel package and I want to use Repository Pattern and put services in it and then inject this Repository to my Controller.
Pay attention that I need a solution in package development.
you may define the provider in the extra section of your package's composer.json file. In addition to service providers, you may also list any facades you would like to be registered:
"extra": {
"laravel": {
"providers": [
"Barryvdh\\Debugbar\\ServiceProvider"
],
"aliases": {
"Debugbar": "Barryvdh\\Debugbar\\Facade"
}
}
},
source: https://laravel.com/docs/9.x/packages#package-discovery
Related
after installing some packages in laravel we should add class definition to providers array. as you know we have this array:
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
// ...
App\Providers\AnnotationsServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
],
my question is how can i add class to this array programical? does any ability in laravel to add it? for example:
App::install();
If you're using a later or equal version of Laravel 5.5, you can use your package's composer.json file to register your classes automatically by using Laravel's package discovery feature:
"extra": {
"laravel": {
"providers": [
"Foo\\Bar\\ServiceProvider"
],
"aliases": {
"Bar": "Foo\\Bar\\Facade"
}
}
}
to add providers and aliases into the application's runtime configuration. Many packages support it now without doing anything.
I am using Laravel 5.8 and I created a custom class named StatusLib.php in the app/library folder.
StatusLib.php
namespace App\library;
class StatusLib
{
CONST SUCCESS = '100';
CONST SUCCESSWITHMESSAGE = '101';
}
I can call this status .
StatusLib::SUCCESS
When I add this following use code in the controller.
use app\library\StatusLib;
How can I add this StatusLib class in autoload and access from anywhere in the project?
Namespaces are case-sensitive.
In your StatusLib class you have App\library;, however, in your controller you've used app\library -- these are not the same.
Change your use statement in your controller to be:
use App\library\StatusLib;
You may also need to run:
composer dumpautoload
Just FYI, Laravel comes with the app directory already set up for autoloading.
In your composer.json file, after the classmap array, add a psr-0:
"autoload" :{
"classmap": [
...
],
"psr-0": {
"library": "app/"
}
}
Run composer dump-autoload.
Hope it helps.
where do you want to use it?
it will be automatically autoloaded because app folder is loaded in composer.json
here:
"autoload": {
"psr-4": {
"App\\": "app/"
},
},
I am using 3 packages in my Laravel 5.8 application:
Backpack CRUD (which uses Backpack Base) https://github.com/Laravel-Backpack/CRUD
Styde\HTML https://github.com/StydeNet/html/
Prologue\Alerts https://github.com/prologuephp/alerts
These are clashing because Backpack Base relies on the Global Alias for "Alert" being set to use PrologueAlert. See an example of how it uses \Alert here:
private function checkLicenseCodeExists()
{
if ($this->app->environment() != 'local' && !config('backpack.base.license_code')) {
\Alert::add('warning', "<strong>You're using unlicensed software.</strong> Please ask your web developer to <a target='_blank' href='http://backpackforlaravel.com'>purchase a license code</a> to hide this message.");
}
}
Source: https://github.com/Laravel-Backpack/Base/blob/1.1.4/src/BaseServiceProvider.php#L264
Because I haven't bought that license yet I started seeing an error caused because that above snippet was trying to pass a string to Alert::add() but it was calling the add() method on Styde\Html\Alert\Container::add() which expects the parameter to be an instance of Styde\Html\Alert\Message instead of calling it on Prologue's version of Alert which accepts a string. It's calling the wrong "Alert"!
Even though my application is specifically set to use PrologueAlert for Alert
// config/app.php
'aliases' => [
...
'Alert' => Prologue\Alerts\Facades\Alert::class
]
I have discovered the reason is that in version 1.7 Styde moved the Aliases for his package from the protected $globalAliases variable on HTMLServiceProvider.php to the composer.json auto-discover section
"extra": {
"laravel": {
"providers": [
],
"aliases": {
"Field": "Styde\\Html\\Facades\\Field",
"Alert": "Styde\\Html\\Facades\\Alert",
"Menu": "Styde\\Html\\Facades\\Menu",
"Form": "Collective\\Html\\FormFacade",
"Html": "Collective\\Html\\HtmlFacade"
},
"dont-discover": [
"laravelcollective/html"
]
}
}
Source: https://github.com/StydeNet/html/commit/f51138fb42bef458f3f0e101b98344162b7327ba#diff-b5d0ee8c97c7abd7e3fa29b9a27d1780
Now, it seems my application is prioritising Styde's alias of "Alert" over my own application-set value!
Other than rolling back to use version 1.6 of Styde, how can I force Laravel to prioritise my own defined aliases over ones discovered via the composer.json?
I found the solution! It was actually inspired by a snippet in my original post.
You can add an extra section to your application's composer.json that get read by the Laravel application and used to decide which packages to ignore during auto-discover like this:
// composer.json
{
...
"extra": {
"laravel": {
"dont-discover": [
"styde/html"
]
}
}
}
This then allows you to pick and choose aliases from the problematic package and define as many or as few of the them as you like in your config/app.php (for my application I was only using the Field alias from Styde/Html so that was the only one I had to add to my App config).
I think as more and more package maintainers start leveraging the auto-discover feature this is going to become a more widely used feature.
Afterthought: This is a shift in the relationship between Composer and Laravel. Whereas the composer.json file was traditionally just a package manager that would be run at installation and then not used when the application is running, it is now a config file that is read by the application. I learned this the hard way as our pipeline that packages-up and deploys the code used to tidy up files that weren't required in the production environment. It was deleting composer.json which started the error happening again in our QA environment.
Whenever I wanted to add functionality to a class in Laravel, lets say the Filesystem class, I would create my own class:
class FilesystemServiceProvider extends LaravelFilesystemManager{
and add it to my providerarray in config/app.php and disable the original:
<?php
'providers' => [
// 'Illuminate\Filesystem\FilesystemServiceProvider',
'MyApp\Filesystem\FilesystemServiceProvider',
],
If I have a package from composer that is bind by Package Discovery how can I prevent it from being discovered?
If you are the consumer of a package and would like to disable package discovery for a package, you may list the package name in the extra section of your application's composer.json file:
"extra": {
"laravel": {
"dont-discover": [
"barryvdh/laravel-debugbar"
]
}
},
I've forked https://github.com/jasonlewis/basset and is now trying to add my fork to my project. But it doesn't seem to read my forked composer.json file after I've run composer update, why? What am I doing wrong?
I've added this repository after require: {}:
"repositories": [
{
"type":"package",
"package": {
"name": "marwelln/basset",
"version":"master",
"source": {
"url": "https://github.com/Marwelln/basset.git",
"type": "git",
"reference":"master"
}
}
}
],
My forked composer.json looks like this (nothing is changed from the original except name):
{
"name": "marwelln/basset",
"description": "A better asset management package for Laravel.",
"keywords": ["assets", "basset", "laravel"],
"license": "BSD-2-Clause",
"authors": [
{
"name": "Jason Lewis",
"email": "jason.lewis1991#gmail.com"
}
],
"require": {
"php": ">=5.3.0",
"kriswallsmith/assetic": "1.1.*"
},
"require-dev": {
"mockery/mockery": ">=0.7.2",
"illuminate/config": "4.0.*",
"illuminate/console": "4.0.*",
"illuminate/filesystem": "4.0.*",
"illuminate/log": "4.0.*",
"illuminate/routing": "4.0.*",
"illuminate/support": "4.0.*",
"symfony/process": "2.3.*"
},
"suggest": {
"aws/aws-sdk-php": "Deploy static assets directly to your S3 buckets.",
"rackspace/php-cloudfiles": "Deploy static assets directly to your Cloud Files container."
},
"autoload": {
"psr-0": {
"Basset": "src/"
},
"classmap": [
"tests/Cases/FilterTestCase.php"
],
"files": ["src/helpers.php"]
},
"extra": {
"branch-alias": {
"dev-master": "4.0-dev"
}
},
"minimum-stability": "dev"
}
With this, the Basset namespace isn't registered in autoload_namespace.php nor am getting "kriswallsmith/assetic": "1.1.*", but if I use the original require: { "jasonlewis/basset" : "dev-master"} it adds it just fine. What is it I'm missing?
You've done some things that are considered not the best practice with Composer.
First of all, you should try to avoid including repositories of the type "package" with all the details of where to find the stuff you need. This will become a maintenance nightmare in the long run. Packages should only be included in your composer.json if you are absolutely sure the maintainer of the software will not include a composer.json file himself. The documentation states on http://getcomposer.org/doc/04-schema.md#repositories:
package: If you depend on a project that does not have any support for composer whatsoever you can define the package inline using a package repository. You basically just inline the
composer.json object.
This case does not apply here, because you maintain the repository to be used yourself and should be able to put in a composer.json.
Now the process of forking and extending an existing library and then using that within your code is supported by Composer, but not the way you did it. First of all, you SHOULD replace the name of the vendor, because you take over that role, and your repository and the software should be distinguishable from other packages. So it is the correct thing to rename "jasonlewis/basset" into "marwelln/basset" and only use that name if you want to reference your own version.
Now the problem might be that if you forked a popular library, and are using other libraries that do require the original, you'll end up adding both packages. That's what the "replace" field is for: You can state in your own composer.json that you think your package is able to replace the original software. Some details are here: http://getcomposer.org/doc/04-schema.md#replace
I gave a detailed answer on how "replace" works here: How does the "replace" property work with composer?
In the end, I think you should do the following (and you still can change that):
Clone the original, change the composer.json to bear your own vendor name as the "name" and add a "replace" with the version of the original software you are changing. You should probably be strict about the version, because you really only replace the version you know about. If later you still know you replace a newer version, you can change the "replace" info.
Then you have to add your own repository as you did, and require the software name with your own vendor name.
You probably did most of that at some point in time, but the step with adding the replacement info is the missing link.
I changed repository to this:
"repositories": [
{
"type":"vcs",
"url": "https://github.com/Marwelln/basset"
}
],
And then used jasonlewis/basset instead of marwelln/basset. It's now working as it should.