Does defaults() method exist in Password? - laravel

i made a service provider to validate the password in Laravel 8, but i get this error:
Call to undefined method Illuminate\Validation\Rules\Password::defaults()
PasswordRuleServiceProvider was added in app.php
// Custom Service Providers
App\Providers\PasswordRuleServiceProvider::class,
This is the provider:
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Validation\Rules\Password;
class PasswordRuleServiceProvider extends ServiceProvider
{
public function register()
{
//
}
public function boot()
{
Password::defaults(function () {
$rule = Password::min(8)->letters()->mixedCase()->numbers()->symbols()->uncompromised(3);
return $rule;
});
}
}
I followed the Laravel doc to do this but it doesn't work, does the defaults method exist in Password? Thanks.

As you can see in the commit history of that Password class, this method did not exist until Laravel v8.42.0 (released on May 18th 2021). Make sure that you are using at least that version if you want to call such a method.
Next time, you should check the source code in your project for such methods, and not any other version on the internet. The source code you've linked might be newer than that

Related

Laravel Package: How to register a third party facade inside a custom package?

I'm creating a package that uses internally this hashid package.
How can I register a third party facade inside a custom package?
I tried three options and none of them worked.
Version - Composer
"aliases": {
"Hashids": "Vinkla\\Hashids\\Facades\\Hashids"
}
Version - inside my ServiceProvider with alias
class MyPackageServiceProvider extends ServiceProvider
{
public function register()
{
...
$this->app->alias(\Vinkla\Hashids\Facades\Hashids::class, 'Hashids');
}
Version - inside my ServiceProvider with AliasLoader
class MyPackageServiceProvider extends ServiceProvider
{
public function register()
{
...
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Hashids', \Vinkla\Hashids\Facades\Hashids::class);
}
When I'm testing the code, I get the error:
Error: Call to undefined method Vinkla\Hashids\Facades\Hashids::encode()
inside
/** #test */
public something_to_test()
{
dd(\Hashids::encode(1));
}
Ok I found one solution, but I am still confused why it is like that.
In my "MyPackageServiceProvider" I need to add:
$this->app->register(HashidsServiceProvider::class);
Why do I need to register a Provider? I thought the composer is handling the work.
At the end only this works:
$this->app->register(HashidsServiceProvider::class);
$loader = \Illuminate\Foundation\AliasLoader::getInstance();
$loader->alias('Hashids', \Vinkla\Hashids\Facades\Hashids::class);
The other versions doesn't work as well :(

IoC resolving issue after upgrading to 5.8

Hoping someone can help me,
I am updating from version 5.7 to 5.8 and I am now having issues with our repository setup.
I am using the repository pattern, for each repository we have a contract. I have a service provider (this is setup to be deferred) to bind the contracts to the repositories so when type hinted the interfaces / contracts in the controllers the repository is injected in.
We also have a service provider (also setup to be deferred) that when the repository is resolved it gets some config data from a config file and calls methods on the repository to setup attributes.
This all worked great on 5.7 but after upgrading to 5.8 it doesn't. If I switch the controllers to type hint the repository instead of the contract it works, but obviously if / when we change the repository we would have to amend all places this is referenced, completely against purpose of coding to an interface and injecting this.
Hopefully I've explained that well enough!
Has anyone come up against this or similar? I've checked the upgrade notes and 5.8 no longer uses the defer property as it implements the interface which I am doing but I can't see anything else and I am struggling to debug it any further.
https://laravel.com/docs/5.8/upgrade#deferred-service-providers
Any help any one can offer would be great.
If I switch back to 5.7 there is no issue, or if use the actual repository and typehint this in the controller there is no issue, it is happening only when using the contract / interface
Here is the service provider for the Repository to set the properties of it
<?php
namespace App\Providers\Repositories\Erp;
use App\Models\ERP_OLTP\WorkOrderStatus as WorkOrderStatusModel;
use App\Repositories\Erp\EloquentMaterialRequirements;
use Illuminate\Contracts\Config\Repository as ConfigRepositoryInterface;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Support\ServiceProvider;
class MaterialRequirementsServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register()
{
$this->app->resolving(
EloquentMaterialRequirements::class,
function (EloquentMaterialRequirements $repo, $app) {
$config = $app[ConfigRepositoryInterface::class]->get('materialRequirements');
$statusIds = array_reduce(
$config['workOrderStatuses'],
function ($acc, $statusCode) {
$acc[] = WorkOrderStatusModel::STATUS[$statusCode];
return $acc;
},
[]
);
$repo->setDemandStatusIds($statusIds);
$repo->setDemandWeekCount($config['weekCount']);
$repo->setAverageUsageWeekCount($config['averageWeeklyUsageMaxAgeWeeks']);
}
);
}
public function provides()
{
return [
EloquentMaterialRequirements::class,
];
}
}
Here is the service provider for repositories to be binded to contracts
<?php
namespace App\Providers;
use Illuminate\Contracts\Config\Repository as ConfigRepositoryInterface;
use Illuminate\Contracts\Support\DeferrableProvider;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider;
class ErpRepositoriesServiceProvider extends ServiceProvider implements DeferrableProvider
{
public function register()
{
foreach ($this->getBindings() as $contract => $implementation) {
$this->app->bind($contract, $implementation);
}
}
public function provides()
{
$services = [];
foreach (array_keys($this->getBindings()) as $contract) {
$services[] = $contract;
}
return $services;
}
private function getBindings(): array
{
return $this->app[ConfigRepositoryInterface::class]->get('repositories.bindings');
}
}
here is the config.repositories, i've removed other repositories to minify it
<?php
use App\Contracts\Erp\Repositories as Contracts;
use App\Managers\Erp\Repositories as Managers;
use App\Repositories\Erp as Repositories;
return [
'bindings' => [
Contracts\MaterialRequirements::class => Repositories\EloquentMaterialRequirements::class,
],
];
It simply never calls the MaterialRequirementsServiceProvider or if it does it isn't resolving the EloquentMaterialRequirements::class and therefore setting properties. I get no errors, no exceptions, nothing to go off

How to extend a laravel package within laravel 5.8 application?

I am new to Laravel and would appreciate any help on describing how a Laravel package residing in vendor folder can be extended and wont get affected if I update the package.
I'll try to create a brief guide, and we'll expand if need be.
I suggest putting all of your files inside a separate directory / namespace. You'll benefit from this should you decide to create your own composer package afterwards.
As an example I'll extend bumbummen99/shoppingcart package which forks the great gloudemans/shoppingcart, adding support for Laravel 5.8 and some minor functionality. You will of course first need to install that package:
composer require bumbummen99/shoppingcart
Start by making a couple of folders. You can use any name for folders / classes, this is what I used, relative to the project root:
app/Repositories/ExtendedCart
app/Repositories/ExtendedCart/Facades
Create the file
app/Repositories/ExtendedCart/ExtendedCart.php
This class will extend the package's main class:
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\Cart;
class ExtendedCart extends Cart
{
public function myMethod(){
return 'myMethod';
}
}
Then make your Service Provider. Create the file:
app/Repositories/ExtendedCart/ExtendedCartServiceProvider.php
(I'm not using artisan as generating / moving the provider will produce wrong namespace)
This is your Service Provider content, here you reference the class that extends the package's class. Note you overwrite the binding from the original package.
namespace App\Repositories\ExtendedCart;
use Gloudemans\Shoppingcart\ShoppingcartServiceProvider;
class ExtendedCartServiceProvider extends ShoppingcartServiceProvider
{
public function register()
{
$this->app->bind('cart', 'App\Repositories\ExtendedCart\ExtendedCart');
}
}
Then register your service provider in config/app.php
'providers' => [
...
//Add this line to the end of providers array
App\Repositories\ExtendedCart\ExtendedCartServiceProvider::class,
]
Lastly create a Facade, which will instantiate the class (otherwise you will get non-static method exceptions). Create this file:
app/Repositories/ExtendedCart/Facades/ExtendedCart.php
This is the contents of the file:
namespace App\Repositories\ExtendedCart\Facades;
use Illuminate\Support\Facades\Facade;
class ExtendedCart extends Facade {
protected static function getFacadeAccessor() { return 'cart'; }
}
You're all set to use your extended methods. You can safely upgrade the original package, and you can even use the default facade:
namespace App\Http\Controllers;
use Cart;
class SomeController extends Controller{
public function someFunction(){
Cart::instance('default')->myMethod();
//This should return 'myMethod'
}
}
I hope this helps, good luck!

Laravel - Share data with all views when the data is available

I'm writing a web app using Laravel 5.6. I need a list of all the connections the current session user have, in all the views.
I tried something like this
View::share('connections', Connection::getList(Auth::id()))
I put this code inside the boot function of AppServiceProvider. But the problem arises when the user isn't already logged in, because at that time Auth::id() is set to null.
The connection list is not generated when the user logs in. This throws the following error:
connections variable is not defined.
This target can achieve through different method,
1. Using BaseController
The way I like to set things up, I make a BaseController class that extends Laravel’s own Controller, and set up various global things there. All other controllers then extend from BaseController rather than Laravel’s Controller.
class BaseController extends Controller
{
public function __construct()
{
//its just a dummy data object.
$user = User::all();
// Sharing is caring
View::share('user', $user);
}
}
2. Using Filter
If you know for a fact that you want something set up for views on every request throughout the entire application, you can also do it via a filter that runs before the request — this is how I deal with the User object in Laravel.
App::before(function($request)
{
// Set up global user object for views
View::share('user', User::all());
});
OR
You can define your own filter
Route::filter('user-filter', function() {
View::share('user', User::all());
});
and call it through simple filter calling.
Update According to Version 5.*
3. Using View Composer
View Composer also help to bind specific data to view in different ways. You can directly bind variable to specific view or to all views. For Example you can create your own directory to store your view composer file according to requirement. and these view composer file through Service provide interact with view.
View composer method can use different way, First example can look alike:
You could create an App\Http\ViewComposers directory.
Service Provider
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer("ViewName","App\Http\ViewComposers\TestViewComposer");
}
}
After that, add this provider to config/app.php under "providers" section.
TestViewComposer
namespace App\Http\ViewComposers;
use Illuminate\Contracts\View\View;
class TestViewComposer {
public function compose(View $view) {
$view->with('ViewComposerTestVariable', "Calling with View Composer Provider");
}
}
ViewName.blade.php
Here you are... {{$ViewComposerTestVariable}}
This method could help for only specific View. But if you want trigger ViewComposer to all views, we have to apply this single change to ServiceProvider.
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider {
public function boot() {
view()->composer('*',"App\Http\ViewComposers\TestViewComposer");
}
}
Reference

How to register a namespace in laravel 4

The problem:
class PostRepostioryInterface not found for line 4 in PostController.php
or in tinkering with the namespace I've even got class
App\Models\Interfaces\PostRepositoryInterface not found
The questions: How to register a namespace in laravel 4? What do I need to do to get L4 to recognise the classes/interfaces at this namespace?
Larave 3 had a $namespaces static object in ClassLoader where you could add namespaces by
Autoloader::namespaces(array(
'App\Models\Interfaces' => path('app').'models/interfaces',
));
I'm not sure if I have that right for laravel 3 but either way, AutoLoader doesn't exist in Laravel 4 and ClassLoader exists but the method namespaces doesn't exist in ClassLoader in Laravel 4.
I've looked at this but it doesn't seem to work without registering the namespace somehow.
Using namespaces in Laravel 4
Example structure:
app/models/interfaces
PostRepostitoryInterface.php
app/models/repositories
EloquentPostRepository.php
namespaces:
App\Models\Repositories;
App\Models\Interfaces;
the files:
PostRepositoryInterface.php
<?php namespace App\Models\Interfaces;
interface PostRepositoryInterface {
public function all();
public function find($id);
public function store($data);
}
EloquentPostRepository.php
<?php namespace App\Models\Repositories;
use App\Models\Interfaces\PostRepositoryInterface;
class EloquentPostRepository implements PostRepositoryInterface {
public function all()
{
return Post::all();
}
public function find($id)
{
return Post::find($id);
}
public function store($data)
{
return Post::save($data);
}
}
PostController.php
<?php
use App\Models\Interfaces\PostRepositoryInterface;
class PostsController extends BaseController {
public function __construct( PostRepositoryInterface $posts )
{
$this->posts = $posts;
}
Thanks
You probably forgot to do composer dump-autoload. This updates the list of classes Laravel autoloads.
You can read more on composer documentation.
On the laravel irc channel I found out the namespaces should work in L4 without a need for registering them anywhere. This is because the composer dump-autoload adds them to the composer/autoload file for me. So that was not an issue.
The issue turned out to be a typo apparently(I can't find it in the code above but after going through every line copy/pasting the class names and namespaces something changed), and also somehow in my real code I left out the 'use' statement for EloquentPostRepository.php
use App\Models\Interfaces\PostRepositoryInterface;
Now I've hit another wall trying to use the namespaced interface with ioc and the controller constructor (target interface App\Models\Interfaces\PostRepositoryInterface is not instantiable) but I guess that should be a different question.

Resources