I have a project with multiple migration files, according to different modules of the project. I want to pass a key (associative array) and run all the files on that index.
//EXAMPLE
$files = [
'blog' => [
//array of file names
],
'storage' => [
//array of file names
],
'sales' => [
//array of file names
],
]
runAll($files['sales'])
I've read the docs but it just allow specified class name in terminal.
Edit: Just checked again and it either allow class name but namespace on migrate command.
For those coming here wondering how to run one specific migration file in Codeigniter 4:
Unfortunately, at the time of writing this post, I couldn't find a direct command/way to handle this task.
Luckily, you can have access to the methods available within the MigrationRunner class in your own source code.
Usage Example Here
Even better, you have the ability to create your own custom commands.
With that in mind, I created a custom command to support running a single migration file.
Custom Command
Step 1:
Generate the basic command file by running the command below in your terminal:
php spark make:command MigrateFile --command migrate:file --group Database --suffix Command
This will create/generate a command file in the path: APPPATH\Commands\MigrateFileCommand.php
Step 2:
Edit this new command file (app/Commands/MigrateFileCommand.php) to something similar to the source code below:
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use Config\Services;
class MigrateFileCommand extends BaseCommand
{
/**
* The Command's Group
*
* #var string
*/
protected $group = 'Database';
/**
* The Command's Name
*
* #var string
*/
protected $name = 'migrate:file';
/**
* The Command's Description
*
* #var string
*/
protected $description = 'Migrates a single migration file.';
/**
* The Command's Usage
*
* #var string
*/
protected $usage = 'migrate:file [arguments] [options]';
/**
* The Command's Arguments
*
* #var array
*/
protected $arguments = [
'name' => 'The valid migration file path beginning from the ROOTPATH. For example: php spark migrate:file "app\Database\Migrations\2022-02-16-101819_AddBlogMigration.php"'
];
/**
* The Command's Options
*
* #var array
*/
protected $options = [
'--namespace' => 'Set migration namespace. Default: "App".',
'--dbgroup' => 'Set database group. Default: "default".',
];
/**
* Actually execute a command.
*
* #param array $params
*/
public function run(array $params)
{
CLI::write("Running migration...", 'yellow');
$message = "";
$paramsSize = count($params);
if (!$paramsSize) {
$message = 'Too few arguments passed. Missing "migration file path."';
} else if ($paramsSize > 1) {
$message = 'Too many arguments passed.';
}
if ($paramsSize !== 1) {
CLI::write(sprintf('Invalid Params: %s', $message), 'red');
CLI::newLine();
$this->showHelp();
return;
}
$runner = Services::migrations();
$namespace = ($params['namespace'] ?? CLI::getOption('namespace')) ?: "App";
$dbgroup = ($params['dbgroup'] ?? CLI::getOption('dbgroup')) ?: "default";
try {
if (!$runner->force(ROOTPATH . $params[0], $namespace, $dbgroup)) {
CLI::error(lang('Migrations.generalFault'), 'light_gray', 'red'); // #codeCoverageIgnore
}
$messages = $runner->getCliMessages();
foreach ($messages as $message) {
CLI::write($message);
}
CLI::write('Done migration.', 'green');
// #codeCoverageIgnoreStart
} catch (\Throwable $e) {
$this->showError($e);
// #codeCoverageIgnoreEnd
}
}
}
The source code above is essentially making use of the force(...) method to execute a single migration file.
Step 3:
Now moving forward, you can easily run a single migration file using the command below in your terminal.
php spark migrate:file "app\Database\Migrations\2022-02-16-101819_AddBlogMigration.php"
Sample Output:
CodeIgniter v4.1.4 Command Line Tool - Server Time: 2022-02-16 13:09:34 UTC+01:00
Running migration...
Running: (App) 2022-02-16-101819_App\Database\Migrations\AddBlogMigration
Done migration.
If in case your migration file resides in a different namespace other than App, for example in a different module ('Modules\Sales'), you can pass an option defining the specific namespace.
The command also supports passing a different database group other than 'default'. I.e:
php spark migrate:file "app\Database\Migrations\2022-02-16-101819_AddBlogMigration.php" --namespace "Modules\Sales" --dbgroup "tests"
You can view the documentation of the new command by running the command below:
php spark help migrate:file
Sample Output:
CodeIgniter v4.1.4 Command Line Tool - Server Time: 2022-02-16 15:16:31 UTC+01:00
Usage:
migrate:file [arguments] [options]
Description:
Migrates a single migration file.
Arguments:
name The valid migration file path beginning from the ROOTPATH. For example: php spark migrate:file "app\Database\Migrations\2022-02-16-101819_AddBlogMigration.php"
Options:
--namespace Set migration namespace. Default: "App".
--dbgroup Set database group. Default: "default".
Bonus Tip
If for some reason you wish to run the new command from within your own code or Controller, this is possible by using:
echo command('migrate:file "app\Database\Migrations\2022-02-16-101819_AddBlogMigration.php"');
You can migrate a single file regardless of order or batches using the method force(string $path, string $namespace, ?string $group = null) available within the MigrationRunner class.
force($path, $namespace, $group)
This forces a single file to migrate regardless of order or batches.
Method “up” or “down” is detected based on whether it has already been
migrated.
Note:
This method is recommended only for testing and could cause data
consistency issues.
So in your case, you would just run a for loop through the files as you pass the expected parameters in the force(...) method. I.e:
Assuming the array keys of your $files array represent the various 'modules' of the project:
$migrate = \Config\Services::migrations();
$psr4 = config(\Config\Autoload::class)->psr4;
foreach ($files as $module => $filenames) {
$namespace = "Modules\\" . ucwords($module);
foreach ($filenames as $filename) {
try {
$migrate->force($psr4[$namespace] . "\\" . $filename, $namespace);
} catch (\Throwable $e) {
// Do something with the error here...
}
}
}
NOTES:
The above solution assumes that you already mapped your $psr4 namespaces in your application modules to their respective locations on the file system: I.e:
File: app/Config/Autoload.php
// ...
public $psr4 = [
APP_NAMESPACE => APPPATH, // For custom app namespace
'Config' => APPPATH . 'Config',
'Modules\Blog' => ROOTPATH . 'module/blog',
'Modules\Storage' => ROOTPATH . 'module/storage',
'Modules\Sales' => ROOTPATH . 'module/sales',
];
// ...
let's do it like me,
see codes step by step
this my codes modules
in app/config/autoload.php
<?php
namespace Config;
use CodeIgniter\Config\AutoloadConfig;
/**
* -------------------------------------------------------------------
* AUTOLOADER CONFIGURATION
* -------------------------------------------------------------------
*
* This file defines the namespaces and class maps so the Autoloader
* can find the files as needed.
*
* NOTE: If you use an identical key in $psr4 or $classmap, then
* the values in this file will overwrite the framework's values.
*/
class Autoload extends AutoloadConfig
{
/**
* -------------------------------------------------------------------
* Namespaces
* -------------------------------------------------------------------
* This maps the locations of any namespaces in your application to
* their location on the file system. These are used by the autoloader
* to locate files the first time they have been instantiated.
*
* The '/app' and '/system' directories are already mapped for you.
* you may change the name of the 'App' namespace if you wish,
* but this should be done prior to creating any namespaced classes,
* else you will need to modify all of those classes for this to work.
*
* Prototype:
*```
* $psr4 = [
* 'CodeIgniter' => SYSTEMPATH,
* 'App' => APPPATH
* ];
*```
*
* #var array<string, string>
*/
public $psr4 = [
APP_NAMESPACE => APPPATH, // For custom app namespace
'Config' => APPPATH . 'Config',
'Myth\Auth' => APPPATH .'ThirdParty/myth-auth/src',
'Modules\Shared' => ROOTPATH . 'module/shared',
'Modules\Common' => ROOTPATH . 'module/common',
'Modules\Auth' => ROOTPATH . 'module/auth',
'Modules\Home' => ROOTPATH . 'module/home',
'Modules\Payment' => ROOTPATH . 'module/payment',
'Modules\App' => ROOTPATH . 'module/app',
];
/**
* -------------------------------------------------------------------
* Class Map
* -------------------------------------------------------------------
* The class map provides a map of class names and their exact
* location on the drive. Classes loaded in this manner will have
* slightly faster performance because they will not have to be
* searched for within one or more directories as they would if they
* were being autoloaded through a namespace.
*
* Prototype:
*```
* $classmap = [
* 'MyClass' => '/path/to/class/file.php'
* ];
*```
*
* #var array<string, string>
*/
public $classmap = [];
/**
* -------------------------------------------------------------------
* Files
* -------------------------------------------------------------------
* The files array provides a list of paths to __non-class__ files
* that will be autoloaded. This can be useful for bootstrap operations
* or for loading functions.
*
* Prototype:
* ```
* $files = [
* '/path/to/my/file.php',
* ];
* ```
*
* #var array<int, string>
*/
public $files = [];
}
this is my migration
path file =Modules\Common\Database\Migrations\Settting
<?php namespace Modules\Common\Database\Migrations;
use CodeIgniter\Database\Migration;
class Setting extends Migration
{
public function up()
{
//
/*
* Setting
*/
$this->forge->addField([
'id' => ['type' => 'int', 'constraint' => 11, 'unsigned' => true, 'auto_increment' => true],
'key' => ['type' => 'varchar', 'constraint' => 255],
'value' => ['type' => 'varchar', 'constraint' => 255],
'description' => ['type' => 'varchar', 'constraint' => 300],
'status' => ['type' => 'tinyint', 'constraint' => 1, 'null' => 0, 'default' => 1],
'created_at' => ['type' => 'datetime', 'null' => true],
'updated_at' => ['type' => 'datetime', 'null' => true],
'deleted_at' => ['type' => 'datetime', 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addUniqueKey('key');
$this->forge->createTable('setting', true);
}
//--------------------------------------------------------------------
public function down()
{
// drop constraints first to prevent errors
$this->forge->dropTable('setting', true);
}
}
to call it
php spark migrate setting -n 'Module\Common'
for more info go there
https://codeigniter.com/user_guide/dbmgmt/migration.html
Related
I have an endpoint, that allows file upload, everything works fine.
Next thing is to cover the endpoint with proper functional test.
And here's the problem - I can't pass the file to the client making the request.
My test class extends \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase.
static::createClient() method creates an instance of ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client and these Client does not support file uploads.
Beacuse of implementing the Symfony\Contracts\HttpClient\HttpClientInterface which defines public function request(string $method, string $url, array $options = []): ResponseInterface; there's no place for passing files argument.
The allowed options in Client does not support files array.
Internaly it looks like this:
ApiPlatform\Core\Bridge\Symfony\Bundle\Test\Client::request passes to the internal kernelBrowser an empty array in place of files params (2nd array): $this->kernelBrowser->request($method, $resolvedUrl, [], [], $server, $options['body'] ?? null)
How do you test endpoints with file upload by extending Base class for functional API tests which is ApiTestCase?
Here's some code, to help you visualize the problem:
ApiResource definition in entity:
/**
* #ApiResource(
* collectionOperations={
* "file_upload"={
* "method"="post",
* "controller"=FileUpload::class,
* "path"="/api/file-upload-endpoint",
* "deserialize"=false,
* "openapi_context"={
* "requestBody"={
* "content"={
* "multipart/form-data"={
* "schema"={
* "type"="object",
* "properties"={
* "file"={
* "type"="string",
* "format"="binary"
* }
* }
* }
* }
* }
* }
* }
* },
* },
* )
*/
Test class (don't mind the instance of UploadedFile, it's just there, to show you, that it cannot be passed anywhere):
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
And here is what i'm looking for:
<?php
declare(strict_types=1);
namespace App\Tests\Api;
use \ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase;
use Symfony\Component\HttpFoundation\File\UploadedFile;
final class FileUploadTest extends ApiTestCase
{
public function testFileUploadSuccessfully():void
{
$file = new UploadedFile(
TESTS_PROJECT_DIR.'/tests/files/Small_sample_of_jet.jpg',
'Small_sample_of_jet.jpg',
'image/jpeg',
);
static::createClient()->request(
'POST',
'/api/file-upload-endpoint',
[
'headers' => [
'Content-Type' => 'multipart/form-data',
],
],
[
'file'=>$file
]
);
self::assertResponseIsSuccessful();
self::assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
}
}
When modyfing the vendor itself and passing the files to the Client::request and then to the kernelBrowser in place of 2nd empty array, everything works fine (I'm aware of breaking the contract, that's not the issue here ;)).
I'm thinking if there's missing feature of uploading files in ApiTestCase or I just can't find the solution.
Pls halp!
Api Platform version: 2.5.6
PS: I know i can use different client - test.client
$client = static::$kernel->getContainer()->get('test.client');
which is an instance of Symfony\Bundle\FrameworkBundle\KernelBrowser, the same that is used internally by the Api Platform's Client and that supports files array, but that's not the point of my question. I'd like to know how to do file upload with ApiTestCase.
Since the current latest release of api-platform/core (2.5.8) we are able to pass more parameters to kernelBrowser->request via the extra key. This also now includes files!
Here is a very basic example of testing an image upload (implemented based on the official API Platform documentation):
$file = new UploadedFile(
'path/to/images/my_image.png',
'my_image.png',
'image/png',
);
$response = static::createClient()->request('POST', '/upload_image',
[
'headers' => ['Content-Type' => 'multipart/form-data'],
'extra' => [
'files' => [
'file' => $file,
],
],
],
);
I want to be able to add a unique id (Uid) to my logging.
In Example 1: Which is depended on config/logging.php and ProcessorTap files below is not working as expected. The logging is configured to use stdout which refers to the ProcessorTap class that is suppose to add a Uid, when the log statement is created (in accordance with UidProcessor)
Example 2: Which uses purely Mono classes works as expected.
Why isnt Example 1 adding the Uid to the logs, when laravel ("laravel/framework": "5.7.*") should be using Monolog classes as well ?
Example 1: When this api is invoked, the output for Log::info('test') does not include UiD
Route::get('/test', function () {
Log::info('test'); //output = [2020-03-24 04:51:16] local.INFO: test
});
config/logging.php:
'default' => env('LOG_CHANNEL', 'stdout'), //.env LOG_CHANNEL=stdout
'stdout' => [
'driver' => 'monolog',
'handler' => StreamHandler::class,
'with' => [
'stream' => 'php://stdout',
],
'tap' => [
ProcessorTap::class,
],
]
ProcessorTap:
use Monolog\Processor\UidProcessor;
class ProcessorTap
{
/**
* Customize the given logger instance.
*
* #param \Illuminate\Log\Logger $logger
* #return void
*/
public function __invoke($logger)
{
$logger->pushProcessor(new UidProcessor());
}
}
Example 2: Working correctly the Uid (a484a6729e14996c0af1)
is added to the log for $logger->info('test')
use Monolog\Logger;
use Monolog\Processor\UidProcessor;
Route::get('/test', function () {
$logger = new Logger('main');
$logger->pushProcessor(new UidProcessor(20));
$logger->info('test'); // output = [2020-03-24 04:57:26] main.INFO: test [] {"uid":"a484a6729e14996c0af1"}
});
This might be a laravel (5.7)/mono version specific issue, but I was able to resolve the via iterating via the handlers and calling pushProcessor
use Monolog\Processor\UidProcessor;
class ProcessorTap
{
/**
* Customize the given logger instance.
*
* #param \Illuminate\Log\Logger $logger
* #return void
*/
public function __invoke($logger)
{
collect($logger->getHandlers())->each(function ($handler) {
$handler->pushProcessor(new UidProcessor());
});
}
}
I want to execute ZF3 action with zf-console.
I can do this using zend-mvc-console module and it works fine.
For example.
Application/config/module.config.php:
'console' => [
'router' => [
'routes' => [
'cronroute' => [
'options' => [
'route' => 'sync',
'defaults' => [
'controller' => Controller\ConsoleController::class,
'action' => 'syncEvents'
]
]
]
]
]
],
Application/src/Controller/ConsoleController.php
class ConsoleController extends AbstractActionController
{
/**
* Entity manager.
* #var Doctrine\ORM\EntityManager
*/
private $entityManager;
/**
* User Manager
* #var Application\Service\UserManager
*/
private $userManager;
/**
* Constructor.
*/
public function __construct($entityManager, $userManager)
{
$this->entityManager = $entityManager;
$this->userManager = $userManager;
}
public function syncAction()
{
$response = $this->userManager->syncUserInfo();
return $response ? 'Sync Success' : 'Failed to sync';
}
}
But it says that it will be deprecated:
https://zendframework.github.io/zend-mvc-console/intro/#deprecated
It suggest to use zf-console from zfcampus:
https://github.com/zfcampus/zf-console
But I cannot find a way to execute Controller action or to use my build services (like UserManager).
There is example to build Zend Application and retrieve Service manager:
use Zend\Console\Console;
use Zend\Console\ColorInterface as Color;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
chdir(dirname(__DIR__));
require __DIR__ . '/../vendor/autoload.php'; // Composer autoloader
$application = Zend\Mvc\Application::init(require 'config/application.config.php');
$services = $application->getServiceManager();
$buildModel = $services->get('My\BuildModel');
Is there a way to execute Controller action with it? Or Can I load my UserManager service?
I tried to get My UserManager:
$buildModel = $services->get('Application\Service\UserManager');
But receiving error:
PHP Fatal error: Uncaught exception 'Zend\ServiceManager\Exception\ServiceNotFoundException' with message 'Unable to resolve service "Application\Service\UserManager" to a factory; are you certain you provided it during configuration?' in /var/www/html/vendor/zendframework/zend-servicemanager/src/ServiceManager.php:687
The zend-mvc-console module does seem to be on the edge of deprecation. Just like you I was trying to implement zfcampus/zf-console. Since the mvc-console module seems to be (almost) deprecated, I suggest you use something different than (mvc) controllers for your console work. I used a class that can handle the call (in a way zf-console expects).
This is a dummy example I was working on for my project;
This is script that is called on the command line:
use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use Zend\Stdlib\Glob;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
require_once __DIR__ . '/vendor/autoload.php'; // Composer autoloader
$configuration = [];
foreach (Glob::glob('config/{{*}}{{,*.local}}.php', Glob::GLOB_BRACE) as $file) {
$configuration = ArrayUtils::merge($configuration, include $file);
}
// Prepare the service manager
$smConfig = isset($config['service_manager']) ? $configuration['service_manager'] : [];
$smConfig = new \Zend\Mvc\Service\ServiceManagerConfig($smConfig);
$serviceManager = new ServiceManager();
$smConfig->configureServiceManager($serviceManager);
$serviceManager->setService('ApplicationConfig', $configuration);
// Load modules
$serviceManager->get('ModuleManager')->loadModules();
$routes = [
[
'name' => 'dumb',
'route' => '[--foo=]',
'description' => 'Some really cool feature',
'short_description' => 'Cool feature',
'options_descriptions' => [
'foo' => 'Lorem Ipsum',
],
'defaults' => [
'foo' => 'bar',
],
'handler' => function($route, $console) use ($serviceManager) {
$handler = new \Application\Command\DumbCommand();
return $handler($route, $console);
}
],
];
$config = $serviceManager->get('config');
$application = new Application(
$config['app'],
$config['version'],
$routes,
Console::getInstance(),
new Dispatcher()
);
$exit = $application->run();
exit($exit);
The handler function can use the service manager to inject any dependencies to the command handler:
'handler' => function($route, $console) use ($serviceManager) {
/** #var \Doctrine\ORM\EntityManager $entityManager */
$entityManager = $serviceManager->get(\Doctrine\ORM\EntityManager::class);
/** #var mixed $repository */
$contactRepository = $entityManager->getRepository(\Application\Entity\Contact::class);
$handler = new \Application\Command\DumbCommand($contactRepository);
return $handler($route, $console);
}
The command class is placed in a Command folder, it looks like:
<?php
namespace Application\Command;
use Application\Entity\Contact;
use Application\Repository\ContactRepository;
use Zend\Console\Adapter\AdapterInterface;
use ZF\Console\Route;
class DumbCommand
{
/** #var ContactRepository */
private $contactRepository;
public function __construct($contactRepository)
{
$this->contactRepository = $contactRepository;
}
/**
* #param Route $route
* #param AdapterInterface $console
* #throws \Doctrine\ORM\ORMException
*/
public function __invoke(Route $route, AdapterInterface $console)
{
$console->writeLine('Bob was here');
foreach ($this->contactRepository->findAll() as $item) {
/** #var Contact $item */
$console->writeLine($item->getFirstName() . ' was here');
}
}
}
(
This is my solution:
I addedd console command routes to my module.config.php files
'console' => array(
'commands' => array(
array(
'name' => 'sendemail',
'handler' => PostCommand::class,
),
array(
'name' => 'sendsms',
'handler' => SmsTransferCommand::class,
)
)
),
I created a console.php in /public (this will be run with arguments to start a CLI app)
use Zend\Console\Console;
use Zend\ServiceManager\ServiceManager;
use ZF\Console\Application;
use ZF\Console\Dispatcher;
chdir(dirname(__DIR__));
require_once 'vendor/autoload.php'; // Composer autoloader
// Prepare application and service manager
$appConfig = require 'config/application.config.php';
$application = Zend\Mvc\Application::init($appConfig);
$serviceManager = $application->getServiceManager();
// Load modules
$serviceManager->get('ModuleManager')->loadModules();
$config = $serviceManager->get('config');
$routes = $config['console']['commands']; // This depends on your structure, this is what I created (see. 1.)
$application = new Application(
$config['app'],
$config['version'],
$routes,
Console::getInstance(),
new Dispatcher($serviceManager) // Use service manager as a dependency injection container
);
$exit = $application->run();
exit($exit);
I separated my CLI command handlers into the src/Command folder. My CLI command handlers are services I have defined, created by factories. (This is why I use the service manager as the container - see. 2.)
[serviceEmail here is a local class variable, which is loaded by the factory of this command handler.]
/**
* #param Route $route
* #param AdapterInterface $console
*
* #return int
*/
public function __invoke(Route $route, AdapterInterface $console)
{
$mails = $this->serviceEmail->sendMailFromDb();
$console->writeLine('Sent mails: ' . \count($mails), ColorInterface::WHITE, ColorInterface::RED);
return 0;
}
I am working on a project which has Laravel 5.3 version and using Laravel Infyom Generator, somehow it generated all these traits and other test files such as (ApiTest, RepositoryTest, ...etc). when I try to run PHPUNIT I am getting this error Can someone help me to find out why I am getting this error?
PHP Fatal error: Trait 'MakeCustomerTrait' not found in C:\Users\ahmed\dev\gamla\tests\CustomerApiTest.php on line 8
Fatal error: Trait 'MakeCustomerTrait' not found in C:\Users\ahmed\dev\gamla\tests\CustomerApiTest.php on line 8
I want to start making new tests for my project do I need to delete these files? because it keeps giving me that error?
screenshot of CustomerApiTest code:
MakeCustomerTrait
<?php
use Faker\Factory as Faker;
use App\Models\Customer;
use App\Repositories\CustomerRepository;
trait MakeCustomerTrait
{
/**
* Create fake instance of Customer and save it in database
*
* #param array $customerFields
* #return Customer
*/
public function makeCustomer($customerFields = [])
{
/** #var CustomerRepository $customerRepo */
$customerRepo = App::make(CustomerRepository::class);
$theme = $this->fakeCustomerData($customerFields);
return $customerRepo->create($theme);
}
/**
* Get fake instance of Customer
*
* #param array $customerFields
* #return Customer
*/
public function fakeCustomer($customerFields = [])
{
return new Customer($this->fakeCustomerData($customerFields));
}
/**
* Get fake data of Customer
*
* #param array $postFields
* #return array
*/
public function fakeCustomerData($customerFields = [])
{
$fake = Faker::create();
return array_merge([
'name' => $fake->word,
'address_street' => $fake->word,
'address_zip' => $fake->word,
'address_city' => $fake->word,
'address_country' => $fake->word,
'shipping_address_street' => $fake->word,
'shipping_address_zip' => $fake->word,
'shipping_address_city' => $fake->word,
'shipping_address_country' => $fake->word,
'contact_person_id' => $fake->randomDigitNotNull,
'created_at' => $fake->word,
'updated_at' => $fake->word
], $customerFields);
}
}
Actually what is happening is here is autoloader is unable to resolve the class in your code. Laravel uses PSR-4 standards to autoload classes which needs fully qualified name spaces for the class which also represents the path of the file which holds the class.
See it this way that if you want to load a class inside your Laravel app directory at the following address :
app/repositories/users/UserRoleRepository.php
You will specify the namespace of your class like App\repositories\users with class name UserRoleRepository so the autoloader can load your class. Otherwise you have to include the file of your class manually.
You can register custom autoloads in your composer.json and by running the following command composer dump-autoload.
You can find more about it over internet like this
Hope it would help.
I assumed that by default the Log::info calls wouldn't log in production, but they are still coming in.
Im setting production using my .env file
APP_ENV=production
APP_DEBUG=false
Ive tried these commands as well, but no luck
composer dump-autoload
php artisan cache:clear
php artisan optimize
Am i missing something?
For anyone still finding this thread (8 years later):
Configure your log channels in config/logging.php file
Set "level" parameter for your log channel to a .env variable
Example:
'channels' => [
'slack' => [
'driver' => 'slack',
'url' => env('LOG_SLACK_WEBHOOK_URL'),
'username' => 'Lumen Log',
'emoji' => ':boom:',
'level' => env('LOG_LEVEL', 'error'),
]
]
Now you can set the LOG_LEVEL variable in your .env file for each environment
Well, I think that it's too late to search for all the Log::info() and do the proposed answer by #jon__o
if (App::environment('local', 'staging')) {
Log::info($error);
}
But you can still do something. You can override the default Laravel logger instance with your own implementation.
Go to your ApplicationServiceProvider and override the log instance with a custom one:
/**
* Register any application services.
*
* #return void
*/
public function register()
{
$this->registerLogger();
}
/**
* Register the logger instance in the container.
*
* #return MyCustomWriter
*/
protected function registerLogger()
{
$this->app->instance('log', $log = new MyCustomWriter(
new Monolog($this->app->environment()), $app['events'])
);
$log->dontLogInfoOnEnvironmnets(['production', 'staging', 'other']);
return $log;
}
Now you can create your custom writer by just extending the Laravel's Writer and overriding the info() method.
class MyCustomWriter extends \Illuminate\Log\Writer
{
protected $dontInfoOn = [];
/**
* Log an informational message to the logs.
*
* #param string $message
* #param array $context
* #return void
*/
public function info($message, array $context = [])
{
// Since we are providing the app environment to the Monolog instance in out ApplicationServiceProvider
// we can get the environment from the Monolog getName() method
if(!in_array($this->monolog->getName(), $this->dontInfoOn)) {
return parent::info($message, $context);
}
}
/**
* Don't log info() on the supplied environments .
*
* #param array $environments
* #return void
*/
public function dontLogInfoOnEnvironmnets(array $environments)
{
$this->dontInfoOn = $environments;
}
}
This way, you can still keep you Log::info on testing environments without checking every time.
Only the displaying of errors will be suppressed when your application is not in debug mode. The Log::info() function will always log when called.
The simple solution is for you to wrap that Log::info() function in something like this:
if (App::environment('local', 'staging')) {
Log::info($error);
}
Be sure to include the App facade use App; at the top of your file. Alternatively you can use the app() helper to get the environment: $environment = app()->environment();.