Laravel 5.1 Localize Factory Seeder - php

I implemented a new factory to generate random data. But I want to have this random data in the format of de_DE. So usually I create a faker object first, but this is not the case in Laravel 5.1 with the new ModelFactory class. How do I localize this then?
$factory->define(App\Models\AED::class, function($faker) {
return [
'owner' => $faker->company,
'street' => $faker->streetAddress,
'latitude' => $faker->latitude,
'longitude' => $faker->longitude
];
});

In order to change the default locale used by Faker, the easiest way is to simply override the FakerGenerator binding with your own concrete implementation:
// AppServiceProvider.php
$this->app->singleton(FakerGenerator::class, function () {
return FakerFactory::create('nl_NL');
});
On top of your AppServiceProvider.php file add the following lines:
use Faker\Generator as FakerGenerator;
use Faker\Factory as FakerFactory;
For example, the above code will mean all Faker instances are created using the nl_NL provider, thus creating Dutch faker data.
Remember: this has to happen after the DatabaseServiceProvider has been executed, so make sure to put your own AppServiceProvider after all of the Laravel ServiceProviders in your config.php array.

Try
$factory->define(App\Models\AED::class, function($faker) {
$faker->locale = "YOUR_LOCALE";
...
});

Add this either at the top of your ModelFactory.php or in your AppServiceProvider::register() method:
$this->app->singleton(\Faker\Generator::class, function () {
return \Faker\Factory::create('de_DE');
});

You must add Providers eg.
$factory->define(Mylead\Models\UserDetails::class, function($faker) {
$faker->addProvider(new Faker\Provider\pl_PL\Person($faker));
$faker->addProvider(new Faker\Provider\pl_PL\Payment($faker));
return [
'name' => $faker->name,
'surname' => $faker->lastname,
'street' => $faker->streetName,
'city' => $faker->city,
'post_code' => $faker->pesel,
'pesel' => $faker->pesel,
'paypal' => $faker->email,
'bank_name' => $faker->bank,
'bank_account' => $faker->bankAccountNumber,
'created_at' => $faker->dateTime
];
});
For now You can't set manualy Faker locale. It should be changed on Laravel Core

Related

In Laravel can I set a default context for the Log facade

I'm using the Log:: facade a lot and have a helper class called LogHelper which provide me with a static method LogHelper::context() which include many key values I need to track the requests. But having to type it every time for each usage make it error prune and fill not so efficient.
I'm looking for a way to inject the values by default, and allow me to overwrite them if needed specifically.
At the moment this is how I use it,
Log::debug('Request Started', LogHelper::context());
what I'm looking for is to inject the context by default
Log::debug('Request Started');
and have the option to overwrite it, if need it:
Log::debug('Request Started', ['more' => 'context'] + LogHelper::context());
PS, the LogHelper::context() return a simple key => value array which include some staff i need to debug requests, and the reason it do not use the values directly in the message is because i log to graylog as structured data, and this way i can filter by any key.
I have solved this issue by using the tap functionality and $logger->withContext() (note: the latter was added in Laravel 8.49).
You want to create a new class which contains your context logic. I've created an extra Logging folder in app/ in which my logging customizations sit.
app/Logging/WithAuthContext.php:
<?php
namespace App\Logging;
use Illuminate\Log\Logger;
class WithAuthContext
{
public function __invoke(Logger $logger)
{
$logger->withContext([
'ip' => request()?->ip(),
'ua' => request()?->userAgent(),
]);
}
}
Depending on which logging channel(s) you use, you will have to add the class to each one you want to add context to. So in app/config/logging.php:
<?php
use App\Logging\WithAuthContext;
use Monolog\Handler\NullHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
return [
// ...
'channels' => [
// ...
'single' => [
'driver' => 'single',
'path' => storage_path('logs/laravel.log'),
'level' => env('LOG_LEVEL', 'debug'),
'tap' => [WithAuthContext::class],
],
// ...
],
];
There is a way, but it is not pretty. You can create a custom monolog logger driver. The process is described at https://laravel.com/docs/8.x/logging#creating-monolog-handler-channels.
Here's a possible implementation:
class ContextEnrichingLogger extends \Monolog\Handler\AbstractHandler {
private $logger;
public function __construct($level = Monolog\Logger::DEBUG, bool $bubble = true, $underlyingLogger = 'single') {
$this->logger = Log::driver($underlyingLogger);
}
public function handle(array $record) {
$record['context'] += LogHelper::context();
return $this->logger->handle($record);
}
}
Then register this as a custom logger in your config/logging.php:
return [
'default' => 'enriched',
//...
'channels' => [
// ...
'enriched' => [
'driver' => 'monolog',
'handler' => ContextEnrichingLogger::class,
'level' => env('APP_LOG_LEVEL', 'debug'),
"with" => [
"underlyingLogger" => env('LOG_CHANNEL', 'single')
]
]
]
];
I haven't tested this particular one but this is how I've defined other custom loggers.
Note, this is probably also achievable via a custom formatter though I think it's probably the same trouble.

How should I use factories in Laravel when I have default values in DB

I have a factory:
$factory->define(\App\MissingData::class, function (Faker $faker) {
$operations = Operation::all()->pluck('id')->toArray();
$operationId = $faker->randomElement($operations);
$operation = Operation::find($operationId);
$meters = $operation->meters->pluck('id')->toArray();
$arrStatus = ['Done', 'Undone'];
return [
'operation_id' => $operationId,
'meter_id' => $faker->randomElement($meters),
'date_ini' => $faker->dateTimeThisYear,
'date_end' => $faker->dateTimeThisYear,
'status' => $faker->randomElement($arrStatus),
];
});
In my migration, I have:
$table->string('status')->default('Undone');
When I want to insert an array in DB, I always prefer to use factory:
factory(MissingData::class)->create($missingData);
with
return [
'operation_id' => $measure->operation_id,
'meter_id' => $measure->meter_id,
'conso_prod' => $measure->conso_prod,
'date_ini' => $missingDataIni,
'date_end' => $missingDataEnd,
];
The wanted behaviour is to insert the status: 'Undone' configured in DB, but my factory will generate a fake status, so I will always have to send Undone status to my factory, which is not the point of using a DB default.
How am I supposed to manage this. Using factory to create and insert model is a good practice.
Using default in DB is also very practical, I believe they can be used both at the same time, but I don't see how should I do that.
Any idea ?
Your best bet is probably to default the status to undone then have a seperate state for done and any other status' that you may add.
$factory->define(\App\MissingData::class, function (Faker $faker) {
$operations = Operation::all()->pluck('id')->toArray();
$operationId = $faker->randomElement($operations);
$operation = Operation::find($operationId);
$meters = $operation->meters->pluck('id')->toArray();
return [
'operation_id' => $operationId,
'meter_id' => $faker->randomElement($meters),
'date_ini' => $faker->dateTimeThisYear,
'date_end' => $faker->dateTimeThisYear,
'status' => 'Undone',
];
});
$factory->state(\App\MissingData::class, 'done', fn() => ['status' => 'Done']);
Then when you want the status to be done you would use the state like this.
factory(\App\MissingData)->state('done')->create();

Laravel 5.1 factory definition unable to resolve closure for foreign relationships

I'm having trouble defining the factory function to handle foreign relationships for my business model. This is the code for my business model factory. The error message that I am getting is :
Uncaught exception 'ErrorException' with message 'Object of class
Closure could not be converted to string' in
/Users/patricia/Code/thank-views/vendor/laravel/framework/src/Illuminate/Database/Connection.php:390
Stack trace
It seems that it is unable to resolve the id for the user. When I run it in tinker it creates the model with a closure function for those fields. However I want to be able to generate these models to be used for my BusinessTest class. It's unable to resolve these dependencies. I'm not sure whether the best place to resolve these dependencies should be in the ModelFactory or elsewhere in the codebase.
$factory->define(App\Business::class, function (Faker\Generator $faker) {
return [
'slug' => $faker->word,
'name' => $faker->name,
'end_card' => $faker->word,
'white_label' => $faker->boolean,
'white_label_url' => $faker->word,
'payment_header' => $faker->word,
'payment_amount' => $faker->randomNumber(),
'payment_amount_display' => $faker->word,
'payment_cost' => $faker->randomNumber(),
'payment_activated' => $faker->boolean,
'main_user_id' => function () {
return factory(App\User::class)->create()->id;
},
];});
You can it change to:
'main_user_id' => $factory->create(\App\User::class)->id
or:
'main_user_id' => $faker->unique()->numberBetween($min = 1, $max = 50)
or:
'main_user_id' => $faker->unique()->randomDigit

Laravel rename routing resource path names

Can we rename routing resource path names in Laravel like in Ruby on Rails?
Current
/users/create -> UsersController#create
/users/3/edit -> UsersController#edit
..
I want like this;
/users/yeni -> UsersController#create
/users/3/duzenle -> UsersController#edit
I want to do this for localization.
Example from Ruby on Rails;
scope(path_names: { new: "ekle" }) do
resources :users
end
I know this is an old question. I'm just posting this answer for historical purposes:
Laravel now has the possibility to localize the resources. https://laravel.com/docs/5.5/controllers#restful-localizing-resource-uris
Localizing Resource URIs By default, Route::resource will create
resource URIs using English verbs. If you need to localize the create
and edit action verbs, you may use the Route::resourceVerbs method.
This may be done in the boot method of your AppServiceProvider:
use Illuminate\Support\Facades\Route;
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot() {
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]); }
Once the verbs have been customized, a resource route registration such as Route::resource('fotos', 'PhotoController') will
produce the following URIs:
/fotos/crear
/fotos/{foto}/editar
It ain't pretty, but you could define multiple routes that use the same controller function. For example:
Route::get("user/create", "UsersController#create");
Route::get("user/yeni", "UsersController#create");
The only (glaringly obvious downside) being that you're routes will get quite cluttered quite quickly. There is a setting in app/config/app.php where you can set/change your locale, and it could be possible to use that in conjunction with a filter to use the routes and then group those routes based on the current local/language, but that would require more research.
As far as I know, there isn't a way to rename resource routes on the fly, but if you get creative you can figure something out. Best of luck!
You can't change the resource url's.
For this you will need to define/create each route according your needs
Route::get("user/yeni", "UsersController#create");
and if you need more than one languages you can use the trans helper function, which is an alias for the Lang::get method
Route::get('user/'.trans('routes.create'), 'UsersController#create');
I just had the same issue. And managed to recreate some sort of custom resource route method. It probably could be a lot better, but for now it works like a charm.
namespace App\Helpers;
use Illuminate\Support\Facades\App;
class RouteHelper
{
public static function NamedResourceRoute($route, $controller, $named, $except = array())
{
$routes = RouteHelper::GetDefaultResourceRoutes($route);
foreach($routes as $method => $options) {
RouteHelper::GetRoute($route, $controller, $method, $options['type'], $options['name'], $named);
}
}
public static function GetRoute($route, $controller, $method, $type, $name, $named) {
App::make('router')->$type($named.'/'.$name, ['as' => $route.'.'.$method, 'uses' => $controller.'#'.$method]);
}
public static function GetDefaultResourceRoutes($route) {
return [
'store' => [
'type' => 'post',
'name' => ''
],
'index' => [
'type' => 'get',
'name' => ''
],
'create' => [
'type' => 'get',
'name' => trans('routes.create')
],
'update' => [
'type' => 'put',
'name' => '{'.$route.'}'
],
'show' => [
'type' => 'get',
'name' => '{'.$route.'}'
],
'destroy' => [
'type' => 'delete',
'name' => '{'.$route.'}'
],
'edit' => [
'type' => 'get',
'name' => '{'.$route.'}/'.trans('routes.edit')
]
];
}
}
Use it like this in the routes.php:
\App\Helpers\RouteHelper::NamedResourceRoute('recipes', 'RecipeController', 'recepten');
Where the first parameter is for the named route, second the controller and third the route itself.
And something like this to the view/lang/{language}/route.php file:
'edit' => 'wijzig',
'create' => 'nieuw'
This results in something like this:
This is not possible in Laravel as they use code by convention over configuration. A resources uses the RESTfull implementation
Therefore you have to stick to the convention of
GET /news/create
POST /news
GET /news/1
GET /news/1/edit
...

How to create a multilanguage label in Yii

I am wondering if the Yii framework uses the defined Labels atttributes in a multilanguage process.
So if I have
public function attributeLabels() {
return array(
'email' => 'Email address',
'rememberMe' => 'Remember me next time',
'password' => 'Password'
);
}
Will this be translated to some other language? Or do I have to do something manually to work?
Yii doesn't translate it automatically. You need to use the i18n built-in in Yii and manually add the translations and modify the labels as follow:
public function attributeLabels() {
return array(
'email' => Yii::t('account','Email address'),
'rememberMe' => Yii::t('account','Remember me next time'),
'password' => Yii::t('account','Password')
);
}
You can get more info about internationalize you app at Quick Start to Internationalize your application in Yii Framework
Well, you can use the built-in translation system to translate your attribute labels, for example:
public function attributeLabels() {
return array(
'email' => Yii::t('myapp','Email address'),
);
}
and then in messages folder create a directory for your language, for example:
messages\dk\myapp.php
myapp.php should return the translation, for example:
return array('Email address' => 'TRANSLATION...');
Next you need to set the language of your application in the config file for instance.
'language' => 'dk',
I had assumed that Yii AR would run getAttributeLabel through Yii::t. Not wanting to do all that copy and pasting on dozens of models, I added this function to my intermediate AR class:
public function getAttributeLabel($attribute)
{
$baseLabel = parent::getAttributeLabel($attribute);
return Yii::t(get_called_class(), $baseLabel);
}
Now to write a shell command that loops through the models and adds their labels to the message file.

Categories