I need to get the keys of a file inside the config of a module. I created User module using nWidart package. This is the registerConfig function
protected function registerConfig()
{
$this->publishes([
__DIR__.'/../Config/config.php' => config_path('user.php'),
], 'config');
$this->mergeConfigFrom(
__DIR__.'/../Config/config.php', 'user'
);
}
I created a file named menu.php that returns an array with a key items, then tried this
dd(config('user::config.name'))
dd(config('user::menu.items'))
They both return null. I also tried php artisan vendor-publish of UserServiceProvider but it still returns null. How can I return the keys?
update
If I simply do: config() I get a full array of the config arrays and can see my package config file there. But the menu config file is not in there
In Your serviceProvider, register method.
$this->mergeConfigFrom(
__DIR__ . '/../config/master.php',
'master'
);
// Merge configs
$this->mergeConfigFrom(
__DIR__ . '/../config/slave.php',
'slave'
);
Create two files inside config folder
slave.php
<?php
return [
'menu' => [
'OP1',
'OP2',
'OP3',
'OP4',
]
];
master.php
//any other config you want to load
Run php artisan config:cache
and use
dd(config('slave.menu'));
dd(config('master.XXX'));
This will output
array:4 [▼
0 => "OP1"
1 => "OP2"
2 => "OP3"
3 => "OP4"
]
return [
'name' => 'Blog',
'en_name'=>'Blog',
'icon'=>'comment',
'color1'=>'EF6F6C',
'color2'=>'EF6F6C',
'route'=>'blog',
'disable' => false,
'subs'=>[
['name'=>'All Posts','route'=>'blog/list'],
['name'=>'All Categories','route'=>'category/list']
]
];
Related
I have found that using the Artisan::call() command to migrate and then again to seed results in a proper migration but the database is never seeded. This may be a bug or perhaps there is a way to flush the previous command.
For example:
Artisan::call('migrate', [
'--database' => 'tenant',
'--path' => 'database/tenantMigrations',
'--force' => true,
]);
And then:
Artisan::call('db:seed', [
'--database' => 'tenant',
'--class' => 'TenantSeeder',
]);
As you can see, I am running these commands on a freshly created tenant DB to "provision" it. Each of these commands works separately, but not together.
I have tried looking for further documentation on joining the two commands while being able to specify the class of the seeder. This would potentially look like:
Artisan::call('migrate', [
'--database' => 'tenant',
'--path' => 'database/tenantMigrations',
'--force' => true,
'--seed' => true,
'--class' => 'TenantSeeder', // this is the only one I can't do, which is critical
]);
I have also tried running the seeder like:
(new \TenantSeeder)->run();
I get the error: Call to a member function line() on null.
It is also interesting to note that all works properly on my local Homestead environment, but not on a Digital Ocean server managed by Forge.
Edit
My current solution is to put my seeder logic inside of regular classes (that do not extend the base Seeder class) and call these as I displayed above.
You can create a wrapper command with all the options needed, then call the migrate, seed, etc commands individually:
php artisan make:command MigrateAndSeedCommand
The class may look something like:
class MigrateAndSeedCommand extends Command
{
protected $signature = 'migrateandseed {--database=} {--path=} {--force} {--seed} {--class=}';
public function handle()
{
Artisan::call('migrate', [
'--database' => $this->option('database'),
'--path' => $this->option('path'),
'--force' => $this->option('force'),
]);
Artisan::call('db:seed', [
'--database' => $this->option('database'),
'--class' => $this->option('class'),
]);
}
}
Usable via:
php artisan migrateandseed --database=tenants --path=database/tenantMigrations --force --seed --class=TenantSeeder
// or
Artisan::call('migrateandseed', [
'--database' => 'tenant',
'--path' => 'database/tenantMigrations',
'--force' => true,
'--seed' => true,
'--class' => 'TenantSeeder',
]);
EDIT
Use $this instead of Artisan, as well as optionally queueing the commands:
// or $this->queue
$this->call('db:seed', [
'--database' => $this->option('database'),
'--class' => $this->option('class'),
]);
Calling Commands From Other Commands
I have installed payum for laravel 5 but my providers are not updating correctly.
I added 'Payum\LaravelPackage\PayumServiceProvider' to app/config/app.php file.
'providers' => [
...
//All my providers
'Payum\LaravelPackage\PayumServiceProvider',
],
also tried as
'providers' => [
...
//All my providers
Payum\LaravelPackage\PayumServiceProvider::class,
],
anyway the error message i get whenever i try to use artisan to make a controller or any other thing is:
am i missing any configuration for the service provider? any help will be apreciated.
EDIT: i have created a new provider and stopped using the default provider.
i ran php artisan make:provider PayumServiceProvider
and into its register method pasted:
...
public function register()
{
$this->app->resolving('payum.builder', function(\Payum\Core\PayumBuilder $payumBuilder) {
$payumBuilder
// this method registers filesystem storages, consider to change them to something more
// sophisticated, like eloquent storage
->addDefaultStorages()
->addGateway('paypal_ec', [
'factory' => 'paypal_express_checkout',
'username' => 'EDIT ME',
'password' => 'EDIT ME',
'signature' => 'EDIT ME',
'sandbox' => true
]);
});
}
...
Still not working
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
use App\Good;
use App\Image;
class testpost extends Controller
{
//
public function execute(Request $request){
$file = "/Users/local/Desktop/111/2.png";
//$folder = "/Users/local/Desktop/111";
//unlink($file);
dd(Storage::delete($file));
//$status_delete_file=Storage::deleteDirectory($folder);
}
}
I'm trying delete file "/Users/local/Desktop/111/2.png". And Storage does not remove this file or folder 111. No errors, always returns "false". Tried to remove file through standard function PHP "unlink"
unlink($file)
All well removes!
Help me please.
Laravel 5.4
PHP 7.1.1
Laravel Storage Facade used for managing file in $root directory of your Laravel filesystem disk.
'disks' => [
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
],
'public' => [
'driver' => 'local',
'root' => storage_path('app/public'),
'url' => env('APP_URL').'/storage',
'visibility' => 'public',
],
....
],
Please refer to this documentation. If your disk is local then $root directory will be storage/app, or if it public then $root directory will be storage/app/public. All operation: create, move, delete will do inside the defined $root directory.
By the way Laravel use league/flysystem package to handle Storage operation. You can see in the package source code what is Storage::delete() actualy doing.
// flysystem/src/Adapter/Local.php
/**
* #inheritdoc
*/
public function delete($path)
{
$location = $this->applyPathPrefix($path);
return unlink($location);
}
The delete function actually call unlink function. But adding directory prefix before do the operation.
So example: if a you want to delete file uploads/image.jpg in your public disk storage, you just need to call
Storage::delete('uploads/image.jpg')
In laravel 5.3, if I upload a file from a form, it will be stored in own storage directory. Then I should create a symlink to that storage path in public path.
I can't use creating symlinks on my system because of the limitation. How can I upload files directly to public/uploads instead of storage/app/uploads?
I tried to set the path in AppServiceProvider.php but it doesn't work.
public function register()
{
//not working:
$this->app->useStoragePath( $this->app->basePath() . "/upload");
//also not working:
// $this->app->bind('path.storage', function () {
// return $this->app->basePath() . '/upload';
// });
}
by "not working" I mean that it is still uploading into the default storage directory. I cleared also the cache.
Here is the upload part (used in a controller):
$request->image->storeAs("uploads", "uploaded_image.jpg");
Thanks for any hints. :)
In Laravel 5 you now have to do this in config/filesystems.php. You can add a new disk like so:
'disks' => [
'uploads' => [
'driver' => 'local',
'root' => public_path(), // previously storage_path();
],
]
and then do the following to use it:
Storage::disk('uploads')->put('filename', $file_content);
I want to send Monolog logs from my Laravel 5.1 application to Loggly.com online log management service. From all possible environment, including local development.
I have found some outdated libs and complicated ways to do this. So I ended up with very simple solution. Actually, Laravel Monolog Handler already have Loggly Handler out of the box.
Add config info to config/services.php:
'loggly' => array(
'key' => 'ENTER_YOUR_LOGGLY_TOKEN_HERE',
'tag' => 'ProjectName_' .strtolower(env('APP_ENV')),
),
Than add Monolog handler in bootstrap/app.php, before $app is returned:
/*
|--------------------------------------------------------------------------
| Setup Loggly Handler
|--------------------------------------------------------------------------
*/
$app->configureMonologUsing(function($monolog) {
$handler = new \Monolog\Handler\LogglyHandler(config('services.loggly.key'),\Monolog\Logger::DEBUG);
$handler->setTag(config('services.loggly.tag'));
$monolog->pushHandler($handler);
});
Voila! You are getting your Monolog Logs in Loggly dashboard.
UPDATE: (thanks #thitami)
Based on laravel.com/docs/5.6/upgrade
The configureMonologUsing Method
If you were using the configureMonologUsing method to customize the Monolog instance for your application, you should now create a custom Log channel. For more information on how to create custom channels, check out the full logging documentation.
I was able to manage having Laravel's default local log behaviour, and pushing to Loggly in the same time, by tweaking mladen-janjetovic's code a bit. Tested on Laravel 5.3
config/services.php:
'loggly' => [
'key' => 'ENTER_YOUR_LOGGLY_TOKEN_HERE',
'tag' => 'ProjectName_' .strtolower(env('APP_ENV')),
],
bootstrap/app.php:
/*
|--------------------------------------------------------------------------
| Push to Loggly, and save locally.
|--------------------------------------------------------------------------
*/
$app->configureMonologUsing(function($monolog) use ($app) {
$log = $app->make(Illuminate\Log\Writer::class);
$logglyHandler = new \Monolog\Handler\LogglyHandler(config('services.loggly.key'));
$logglyHandler->setTag(config('services.loggly.tag'));
if (config('app.env') == 'production')
{
// Push to Loggly and save local if in production
$log->getMonolog()->pushHandler($logglyHandler);
$log->useFiles(storage_path('/logs/laravel.log'));
}
else
{
// Otherwise, save only locally
$log->useFiles(storage_path('/logs/laravel.log'));
}
});
Alternatively, you may use Monolog-Cascade to do this.
Monolog-Cascade is a Monolog extension that allows you to set up and configure multiple loggers and handlers from a single config file.
Here is a sample config file for Monolog-Cascade using Loggly. This would log to you stdOut and to Loggly:
---
handlers:
console:
class: Monolog\Handler\StreamHandler
level: DEBUG
stream: php://stdout
error_loggly_handler:
class: Monolog\Handler\LogglyHandler
level: ERROR
token: xxxx-xxxx-xxxxxxxx
tags: [cascade, waterfall]
loggers:
my_logger:
handlers: [console, error_loggly_handler]
If you're interested, here is a blog post on Cascade => https://medium.com/orchard-technology/enhancing-monolog-699efff1051d
[Disclaimer]: I am the main contributor of Monolog-Cascade.
Got mine working with little configuration with Laravel 8.
Just use the built-in monolog handler for Loggly.
Edit your app/config/logging.php
use Monolog\Handler\LogglyHandler;
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'loggly'],
'ignore_exceptions' => false,
],
'loggly' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => LogglyHandler::class,
'with' => [
'token' => env('LOGGLY_TOKEN'),
],
],
]
For more advanced logging (for my case I need to set the tag as it was missing in the built-in handler's constructor.
Copy the built-in handler where you can find it within vendor folder
(e.g: vendor/monolog/monolog/src/Monolog/Handler/LogglyHandler.php) into your app folder of choice (e.g: app/Logging/CustomLogglyHandler.php).
Modify the constructor to set the tags, and you need to change some of the imports as we're on different namespaces.
// app/Logging/CustomLogglyHandler.php
namespace App\Logging;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Handler\MissingExtensionException;
use Monolog\Logger;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\LogglyFormatter;
use function array_key_exists;
use CurlHandle;
use Monolog\Handler\Curl\Util as CurlUtil;
public function __construct(string $token, array|string $tag = [], $level = Logger::DEBUG, bool $bubble = true)
{
if (!extension_loaded('curl')) {
throw new MissingExtensionException('The curl extension is needed to use the LogglyHandler');
}
$this->token = $token;
if (is_array($tag)) {
$this->tag = $tag;
} else {
$this->tag = [$tag];
}
parent::__construct($level, $bubble);
}
// config/logging.php
'loggly' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => CustomLogglyHandler::class,
'with' => [
'token' => env('LOGGLY_TOKEN'),
'tag' => strtolower(env('APP_NAME', 'Laravel')) . '_' . strtolower(env('APP_ENV', 'production'))
],
],
To expand on Hassan's contribution (posting as an answer, as I still don't have enough reputation to post a comment).
If you have a need to use daily logs locally, you could use following code:
$logFile = 'laravel'.'.txt';
$log->useDailyFiles(storage_path().'/logs/'.$logFile);
Of course, logfile name is totally arbitrary. In this example, format will be as such:
laravel-YYYY-MM-DD.txt
Edit:
with an upgrade to 5.4 this line does not work anymore:
$log = $app->make(Illuminate\Log\Writer::class);
As a workaround, you can create Writer instance manually, injecting $monolog available from configureMonologUsing closure:
$log = new Illuminate\Log\Writer($monolog);