How to implement Laravel password validation rules as string in arrays? - php

I want to use the out-of-the-box Laravel password validation rules. This is possible by using the use Illuminate\Validation\Rules\Password class.
So you can use those rules like so:
\Illuminate\Validation\Rule\Password::min(8)->letters()->numbers()->mixedCase()->uncompromised(3)
However, you can't use those rules inside a config file, like in this package because you get the following error when running
artisan config:cache
❯ artisan config:cache > ─╯
Configuration cache cleared successfully.
LogicException
Your configuration files are not serializable.
at vendor/laravel/framework/src/Illuminate/Foundation/Console/ConfigCacheCommand.php:84
80▕ require $configPath;
81▕ } catch (Throwable $e) {
82▕ $this->files->delete($configPath);
83▕
➜ 84▕ throw new LogicException('Your configuration files are not serializable.', 0, $e);
85▕ }
86▕
87▕ $this->info('Configuration cached successfully.');
88▕ }
1 bootstrap/cache/config.php:859
Error::("Call to undefined method Illuminate\Validation\Rules\Password::__set_state()")
After reading the docs, it seems that you can't use those password rules as strings inside an array like so:
"password_rules" => ['min:8'],
So checking the available rules, the rest of the following rules (letters, mixedCase, uncompromised) are not available.
Then, is there a workaround to set those password rules inside the config file?
(so that, I can avoid the LogicException: Your configuration files are not serializable. after executing the artisan config:cache command).

use Illuminate\Validation\Rules\Password;
$rules = [
'password' => [
'required',
'string',
Password::min(8)
->mixedCase()
->numbers()
->symbols()
->uncompromised(),
'confirmed'
],
]
Try using the above code it should work.

I am not a Laravel person, but you can put the config into an array and then unpack it later in your app with something like this:
// for illustration
class Mock {
public function __call($name, $args) {
printf("called: %s(%s)\n", $name, implode(', ', $args));
return $this;
}
// this is awful. never do this.
// in Laravel the min() function, and only this function, is basically
// an alias to the constructor, which is weird.
public static function __callStatic($name, $args) {
return (new self())->$name(...$args);
}
}
$params = [
'min' => [8],
'letters' => [],
'numbers' => [],
'mixedCase' => [],
'uncompromised' => [3]
];
$o = NULL;
foreach( $params as $func => $args ) {
if( is_null($o) ) {
$o = Mock::$func(...$args);
} else {
$o = $o->$func(...$args);
}
}
Output:
called: min(8)
called: letters()
called: numbers()
called: mixedCase()
called: uncompromised(3)

Related

Using separate data provider class with PHPUnit and attributes

I would like to separate Tests and Data Providers. Using PHP 8 attributes, I cannot get the following test to run when referencing an external Data Provider:
#[Test]
#[DataProviderExternal(RouterDataProvider::class, 'registerGetRouteData')]
public function itRegistersGetRoute(Route $route, array $expectedResult)
{
$this->router->get($route);
$this->assertEquals($expectedResult, $this->router->getRoutes());
}
My data provider class:
class RouterDataProvider
{
public static function registerGetRouteData(): array
{
return [
$route = new Route('/', ['IndexController', 'index']),
[
'GET' => [
'/' => $route,
],
'POST' => []
]
];
}
}
How could I get this test to run with the desired provider method?
By running PHPUnit with the following flags, I was able to see exactly what my issue was:
./vendor/bin/phpunit --display-deprecations --display-warnings --diplay-errors --display-notices
The data set was invalid. Changing the return to yield and updating the return type for the registerGetRouteData method from array to \Generator resolved this.
I was running phpunit with the --testdox flag, so I'm not sure if this is what stopped me seeing any errors initially and assume the test was being skipped.

How to change the Auth Guard in Laravel Auditing?

I have used the Laravel Auditing plugin (http://www.laravel-auditing.com/docs/3.1) to log the all models changes.Am using different auth system but the Laravel Auditing
getLoggedInUserId()
using laravel core one so need to change that. i have forked this plugin and edited the function directly its worked. But i like to find another ways if you have idea share with me ?
protected function getLoggedInUserId()
{
try {
if (Auth::check()) {
return Auth::user()->getAuthIdentifier();
}
} catch (\Exception $e) {
return;
}
}
Unfortunately, until version 4 of the package, you couldn't change the user resolver without modifying the actual code.
However, from version 4 onwards, you can do so in the configuration file (config/audit.php).
The user resolver can be set in two ways.
As a Closure:
return [
'user' = [
'resolver' => function () {
return Auth::check() ? Auth::user()->getAuthIdentifier() : null;
},
],
];
As a FQCN:
return [
'user' = [
'resolver' => App\User::class,
],
];
TIP: You have to implement the OwenIt\Auditing\Contracts\UserResolver interface in the App\User class for this to work.
See the full documentation here.

Dingo/API when Unit Testing: The version given was unknown or has no registered routes

I built an API using dingo/api 0.10.0, Laravel 5.1 and lucadegasperi/oauth2-server-laravel": "^5.1".
All my routes work fine in Postman/Paw!
The problem appears when I try to test the API using PHPUnit.
This is part of my route-api.php file
<?php
$api = app('Dingo\Api\Routing\Router');
$api->version(['v1'], function ($api) {
$api->post('oauth/access_token', function () {
return response(
\LucaDegasperi\OAuth2Server\Facades\Authorizer::issueAccessToken()
)->header('Content-Type', 'application/json');
});
$api->group(['middleware' => ['oauth', 'api.auth']], function ($api) {
$api->post('/register', 'YPS\Http\Controllers\Api\UserController#register');
});
And this is my test file UserRegistrationTest.php
class UserRegistrationTest extends ApiTestCase
{
public function setUp()
{
parent::setUp();
parent::afterApplicationCreated();
}
public function testRegisterSuccess()
{
$data = factory(YPS\User::class)->make()->toArray();
$data['password'] = 'password123';
$this->post('api/register', $data, $this->headers)
->seeStatusCode(201)
->seeJson([
'email' => $data['email'],
'first_name' => $data['first_name'],
'last_name' => $data['last_name'],
]);
}
public function testRegisterMissingParams()
{
$this->post('api/register', [], $this->headers, $this->headers, $this->headers)->seeStatusCode(422);
}
}
The ApiTestCase simply retrieves a token and sets the headers.
private function setHeaders()
{
$this->headers = [
'Accept' => 'application/vnd.yps.v1+json',
'Authorization' => 'Bearer ' . $this->OAuthAccessToken,
];
}
Now, the weird part is that the first test testRegisterSuccess runs perfectly and returns the response I expect. But the second one testRegisterMissingParams, even though it's the same route, returns this,
array:2 [
"message" => "The version given was unknown or has no registered routes."
"status_code" => 400
]
I tracked the error and it is in the Laravel adapter here:
public function dispatch(Request $request, $version)
{
// it seems that the second time around can't find any routes with the key 'v1'
if (! isset($this->routes[$version])) {
throw new UnknownVersionException;
}
$routes = $this->mergeExistingRoutes($this->routes[$version]);
$this->router->setRoutes($routes);
return $this->router->dispatch($request);
}
And further more, if i run one test at a time (eg comment one out, run test and then comment the other and run test) i see the result expected in both tests. The problem is when i run multiple tests.
Any thoughts on that?
Thank you!
Run php artisan api:routes to see full path you may have missed something for the URL, also if this working if you request your URL manually?
I had same problem with testing using Dingo & Lumen. This worked for me - remove bootstrap="bootstrap/app.php" from phpunit.xml file and change line processIsolation="false" to processIsolation="true".

Initial migrate in laravel 5 with a reference in the ConfigServerProvider fails

In my ConfigServerProvider.php at boot there is a reference to the configs database table. At initial migrate this database table doesn't exist, so I am getting an error. How can I run the first time 'php artisan migrate', while leaving this boot line intact?
public function boot() {
config([
'version' => "1.0.2",
'title' => Config::where('name', 'title')->first()->pluck('value')
]);
}
I added this around the whole config:
if(Schema::hasTable('configs')) { }
And that seems to make all work.
In my app i made this:
try {
$configs = Config::all();
} catch (\Exception $e) {
$configs = [];
}

How to force test fail in Codeception

I am making WebServices tests with Codeception, here is my code:
//Making first query for getting needed parameter
$I->wantTo('Make something');
$I->sendPOST($this->route, [
'token' => Fixtures::get('token'),
'id' => Fixtures::get('some_id')
]);
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->seeResponseContains('"error_message"');
//Then I get what I need with regexp
if (preg_match('/^.*\s(?<value_i_need>\d+)\.$/', $I->grabDataFromResponseByJsonPath('$.status.error_message')[0], $matches)) {
$I->sendPOST($this->route, [
'token' => Fixtures::get('token'),
'id' => Fixtures::get('some_id')
]);
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->seeResponseContains('"something"');
$I->seeResponseContains('"something_else"');
} else {
//And if I don't get needed parameter with regular expression, here I have to force test fail
}
Does anybody know how to force test fail?
Thanks in advance!
You can use the fail action on your actor. i.e.
$I->fail('this test fails... just because');
You can mark your test as skipped or incomplete. Here is example:
public function tryToMakeAwesomeThings(ApiTester $I, Scenario $scenario)
{
if ( ... ) {
// do something
} elseif ( ... ) {
$scenario->incomplete();
} elseif ( ... ) {
$scenario->skip();
}
}
You can use PHPUnit\Framework\Assert::fail() or throw PHPUnit\Framework\AssertionFailedError exception.
There is another problem with Codeception 4 and upper.
Method fail now in Assertion module https://codeception.com/docs/modules/Asserts
This module not included in codeception by default, you must install it separately.
When you install it, this module must be added in config file, such as "api.suite.yml"
actor: ApiTester
modules:
enabled:
...
- \Codeception\Module\Asserts
After this, you need to rebuild codeception and this method appear to use.
Use assertInstanceOf() from https://codeception.com/docs/modules/Asserts
Example:
public function test_array_result() {
/** #var Demo $demo */
$demo = Common::get_which_class( $this->post_id );
self::assertInstanceOf( Demo::class, $demo, 'Unable to instantiate the Demo class.');
$x = [ 'a', 'b', 'c' ];
$this->assertEqualSetsWithIndex( $x, $demo->get_result() );
}

Categories