How to test config file changes? - laravel

I wrote function which changes values in config/app.php using file_put_content.
public function updateConfig($path, $key, $value)
{
$content = file_get_contents($path);
$pattern = "/'" . $key . "' => '[0-9]+'/";
$replacement = "'" . $key . "' => '" . $value . "'";
$content = preg_replace($pattern, $replacement, $content);
file_put_contents($path, $content);
}
$path = base_path() . '/config/app.php';
$key = 'version_number';
$value = '10';
$service->updateConfig($path, $key, $value);
$this->assertEquals(config('app.version_number'), $value);
How can I test it with changing config file?

I presume you want to change the config then use it.
There is a way you can achieve this without editing the config file. Note that, in order to speed up Laravel, configurations are cached and you need to run php artisan clear:cache or manually delete cache files.
If you want to change config on the fly. Change it as shown before using it.
Config::set('app.version_number', 10);

Related

How to Save File in storage folder with Original name?

I want to store an uploaded file with its original client name in the storage folder. What do I need to add or change in my code?Any help or recommendation will be greatly appreciated
Here my Controller
public function store(Request $request) {
$path = "dev/table/".$input['id']."";
$originalName = $request->file->getClientOriginalName();
$file = $request->file;
Storage::disk('local')->put($path . '/' . $originalName, $request->file);
}
Edit: I know how to get the originalClientName. the problem is storing the file in the folder using the original name, not the hash name. It doesn't store in the file in the original it makes a new folder instead here is the output "dev/table/101/Capture1.PNG/xtZ9iFoJMoLrLaPDDPvc4DMJEXkRL3R4qWOionMC.png" what I trying to get is "dev/table/101/Capture1.PNG"
I have tried to use StoreAs Or putFileAs but the method is undefined
I managed to figure out how to store it with a custom name, for those who want to know how to do it here is the code
$id = $input['id'];
$originalName = $request->file->getClientOriginalName();
$path = "dev/table/$id/".$originalName;
Storage::disk('local')->put($path, file_get_contents($request->file));
public function store(Request $request) {
$originalName = $request->file->getClientOriginalName();
$extension = $request->file->getClientOriginalExtension();
$path = "dev/table/" . $input['id'] . "/" . $originalName . "." . $extension;
$file = $request->file;
Storage::disk('local')->put($path, $file);
}
To get the original file name you can use this in your ControllerClass:
$file = $request->file->getClientOriginalName();
To get additional the extension you can use this Laravel Request Method:
$ext = $request->file->getClientOriginalExtension();
Then you can save with:
$fileName = $file.'.'.$ext;
$request->file->storeAs($path, $fileName);
// or
Storage::disk('local')->put($path . '/' . $fileName , $request->file);
You can save files using storage with the default name using putFileAs function instead of put which allow take third param as a file name
$path = "dev/table/101/";
$originalName = request()->file->getClientOriginalName();
$image = request()->file;
Storage::disk('local')->putFileAs($path, $image, $originalName);
Update
You can do something like this with put,
Storage::disk('local')->put($path.$originalName, file_get_contents($image));
I tried to manage like this;
$insurance = $request->file('insurance_papers');
$insuranceExtention = $insurance->getClientOriginalExtension();
$path = "public/files/" . $carrier->id . "/insurance_papers." . $insuranceExtention;
Storage::disk('local')->put($path, file_get_contents($insurance));
You can try this, this is work for me
if ($request->hasFile('attachment')) {
$image = $request->file('attachment');
$imageName = time() . '.' . $image->getClientOriginalExtension();
$path = "foldername/".$imageName;
Storage::disk('public')->put($path, file_get_contents($image));
}

How to override env variables in Laravel Dusk

Unfortunately config(['key' => 'newValue']) doesn't work in a Dusk setup (for overriding a config value), presumably because it would change the config of the system running the test rather than the experience of the headless browser that gets opened to execute the flow.
And sometimes I can see no way around needing to temporarily change an env value for a certain Dusk test.
E.g. temporarily set QUEUE_DRIVER=sync when usually it is 'dusk-connection', but in one particular test, I need to check for values in the 'jobs' tables in the DB.
Before upgrading to Laravel >=5.8 (and therefore newer versions of DotEnv), I was able to use this function called within a Dusk test before $this->browse(...:
/**
* Overrides any .env variables for Dusk tests. https://laracasts.com/discuss/channels/testing/how-to-change-env-variable-config-in-dusk-test
* The changes exist only for that one test because of tearDown.
* Remember that you need to be using `php artisan dusk` instead of `phpunit`.
* https://stackoverflow.com/questions/54407784/laravel-dusk-how-to-change-config-values-before-each-test-for-the-browser#comment103224655_54407784
*
* #param array $variables
*/
protected function overrideDuskEnv($variables = []) {
$path = self::DOT_ENV;
if (file_exists($path)) {
$contentToPrepend = '';
foreach ($variables as $key => $value) {// Convert all new parameters to expected format
$contentToPrepend .= $key . '="' . $value . '"' . PHP_EOL;
}
$originalFileContents = $this->envContents;
$comment = '# ==============================================' . PHP_EOL . '# VARIABLES ABOVE THIS LINE are from "' . __FUNCTION__ . '" function in DuskTestCase ( https://laracasts.com/discuss/channels/testing/how-to-change-env-variable-config-in-dusk-test )' . PHP_EOL;
file_put_contents($path, $contentToPrepend . $comment . $originalFileContents); //"If they are appended, it doesn't seem to take priority."
} else {
throw new \Exception('Could not find env file to override!');
}
}
I was able to call it like this: $this->overrideDuskEnv(['QUEUE_DRIVER' => 'sync']);
But in more recent Laravel versions, environment variables are immutable (see "Read-Only env Helper").
How can I achieve my goal, where Dusk uses .env.dusk.local for most tests but then for certain tests may differ slightly?
Finally after struggling with this problem for 10+ hours, I have a solution.
/**
* #param array $variables
*/
protected function overrideDuskEnv($variables = []) {
$path = self::DOT_ENV;
if (file_exists($path)) {
$contentToAppend = '';
foreach ($variables as $key => $value) {// Convert all new parameters to expected format
$contentToAppend .= $key . '="' . $value . '"' . PHP_EOL;
}
$originalFileContents = $this->envContents;
$comment = '# ==============================================' . PHP_EOL . '# VARIABLES BELOW THIS LINE are from "' . __FUNCTION__ . '" function in DuskTestCase ( https://laracasts.com/discuss/channels/testing/how-to-change-env-variable-config-in-dusk-test )' . PHP_EOL;
$this->baseCommand->consoleOutput('Appending to ' . $path . ': ' . $contentToAppend);
file_put_contents($path, $originalFileContents . $comment . $contentToAppend); //It used to be the case that "If they are appended [rather than prepended], it doesn't seem to take priority", but after the DotEnv upgrade in Laravel 5.8, it seems prepending doesn't work and appending does.
} else {
throw new \Exception('Could not find env file to override!');
}
}
Then in my setUp() function in my Dusk test class, I call:
$this->overrideDuskEnv([
'SIGNUP_FORM_POST_PATH' => \App\Helpers\Routes::SIGNUP,
'QUEUE_DRIVER' => \App\Helpers\ConfigConstants::DUSK_CONNECTION
]);
Then in each test function after the closing of $this->browse(function (Browser $browser)... and before assertions, I call:
config(['queue.default' => \App\Helpers\ConfigConstants::DUSK_CONNECTION]); //this does not affect the headless browser but IS probably necessary here so that assertQueued knows to pull from the queue that the headless browser was using.
The tricky part to understand with Dusk is that the environment variables (and therefore the config arrays) of the console process running the tests differ from those that get used by the headless browser (simulating what a real user would experience).
By the way, I had been so hopeful about approaches like this one, but they turned out to be complete wastes of time because DuskCommand is already calling overload to make the env variables mutable.
See here for a documented approach to overriding config([]) during a dusk test:
https://gist.github.com/wrabit/e01df16858505c395b7b0d271112a023
You can also use a seperate env for all the dusk tests.
It is also mentioned in the laravel docs here https://laravel.com/docs/8.x/dusk#environment-handling
This is a bit easy but if you put any wrong entry then it will burst.
public function store(Request $request) {
foreach ($request->all() as $key => $value) {
$_ENV[$key] = $value;
}
$x = '';
unset($_ENV['_token']);
foreach ($_ENV as $key => $value) {
$x .= $key . "=" . $value . "\n";
}
base_path('.env');
file_put_contents(base_path('.env'), $x);
return redirect()->back();
}
Using
<form class="grid gap-2" action="{{ route('admin.enviroment.store') }}" method="post">
<div>
<x-label for="GOOGLE_TAG" :value="__('GOOGLE_TAG')" />
<x-input id='GOOGLE_TAG' name="GOOGLE_TAG" :value="__($_ENV['GOOGLE_TAG'])" class="w-full rounded-md dark:bg-gray-700" type="text" required />
</div>
#csrf
<x-button class="ml-auto dark:bg-blue-900/90">
{{ __('Update GOOGLE TAG') }}
</x-button>
</form>

i keep getting "function name must be a string" error

I am building a site using laravel, and I got this error when trying to upload an image. I'm a beginner so, can I get some help?
$user = Auth::user();
$user->name = $request('name');
$user->update();
$file = $request->file('image');
$filename = $request->name . '-' . $user->id . '.jpg';
$user->name = $request('name');
$request is variable not func because of $
Because you didn't follow the naming rules in PHP : $request('name') .
I guess you were going to use $request->get('name')
For Uploading image you can use following code, Although I prefer using Intervention Image
//Auth::loginUsingId(1); #You can test your code without a real login
$data = $request->only(['name']);
if (request()->hasFile('image')) {
$file = request()->file('image');
$fileName = md5($file->getClientOriginalName() . time()) . "." . $file->getClientOriginalExtension();
$destinationPath = public_path('/images/'); //// I assume you have a folder named images in public.
$file->move($destinationPath, $fileName);
$data['avatar'] = $destinationPath.$fileName; // I assume you have a field named avatar in users table.
}
return $data; // Try this line for a better understanding then comment it
Auth::user()->update($data);

Laravel deploy: storage image doesn't work correctly

After deploying my laravel project from local to Apache web server, all works correctly except images link. Here the code:
Images are stored in:
storage/app/public/photos
after i've run command:
php artisan storage:link
Images are linked at:
public/storage/photos
Controller:
if ($request->hasFile('photo')) {
$extension = $request->file('photo')->getClientOriginalExtension();
$file = $request->file('photo');
$photo = $file->storeAs('public/photos', 'foto-' . time() . '.' . $extension);
$user->photo = $photo;
$user->save();
}
Images are uploaded correctly on storage/app/public/photos and correctly linked in public/storage/photos but it doesn't display on frontend.
in blade, i've tried to use Storage::url to retrieve the path
{{Storage::url($user->photo)}}
and asset()
{{asset($user->photo)}}
in both cases, image doesn't exist
The public path of image is:
http://mywebsite.com/storage/photos/foto-1522914164.png
You should Use url function to show your image like below way.
url($user->photo);
I'd suggest to change the controller code as follows:
if ($request->hasFile('photo')) {
$extension = $request->file('photo')->getClientOriginalExtension();
$file = $request->file('photo');
$photoFileName = 'foto-' . time() . '.' . $extension;
$photo = $file->storeAs('public/photos', $photoFileName);
$user->photo = 'photos/' . $photoFileName;
$user->save();
}
Then you can use {{asset($user->photo)}} in your blade.
on my webspace, it seems that the only way to display image correctly is to create a custom route that read and serve the image.
i'm solved like this:
i'm storing only image name in db:
if ($request->hasFile('photo')) {
$extension = $request->file('photo')->getClientOriginalExtension();
$file = $request->file('photo');
$photoFileName = 'photo-' . $model->id . '.-' . time() . '.' . $extension;
$photo = $file->storeAs('public/photos', $photoFileName);
$store = $photoFileName;
}
then, i've create custom route that read images and display them:
Route::get('storage/{filename}.{ext}', function ($filename, $ext) {
$folders = glob(storage_path('app/public/*'), GLOB_ONLYDIR);
$path = '';
foreach ($folders as $folder) {
$path = $folder . '/' . $filename . '.' . $ext;
if (File::exists($path)) {
break;
}
}
if (!File::exists($path)) {
abort(404);
}
$file = File::get($path);
$type = File::mimeType($path);
$response = Response::make($file, 200);
$response->header('Content-Type', $type);
return $response;
});
in blade, i'm using Storage to display image:
{{ Storage::url($photo->photo) }}}

Laravel 5.4 Error: NotReadableException: Image source not readable

I'm trying to create multiple copies of profile pic in different sizes when a profile is created. But I am constantly getting this error:
" NotReadableException: Image source not readable"
Can somebody point me what I'm missing in my below code:
public function updateprofile(UserProfileRequest $request){
$user_id = Auth::User()->id;
$profile = UserProfile::where('user_id','=',$user_id)->first();
$profile->fullname = $request->fullname;
if ($request->hasFile('img')) {
if($request->file('img')->isValid()) {
$types = array('_original.', '_32.', '_64.', '_128.');
$sizes = array( '32', '64', '128');
$targetPath = 'public/uploads/'.$user_id;
try {
$file = $request->file('img');
$ext = $file->getClientOriginalExtension();
$fName = time();
$original = $fName . array_shift($types) . $ext;
Storage::putFileAs($targetPath, $file, $original);
foreach ($types as $key => $type) {
$newName = $fName . $type . $ext;
Storage::copy($targetPath . $original, $targetPath . $newName);
$newImg = Image::make($targetPath . $newName);
$newImg->resize($sizes[$key], null, function($constraint){
$constraint->aspectRatio();
});
$newImg->save($targetPath . $newName);
}
$profile->img = 'public/uploads/'.$user_id;
} catch (Illuminate\Filesystem\FileNotFoundException $e) {
}
}
}
$profile->save();}
I had the same issue i ran this command and it worked
php artisan storage:link
This command creates a storage directory under the public folder.
Also use public path function to get the public path
$targetPath = public_path('storage/uploads/'. $user_id);
The 'storage' used inside the laravel public_path() function is used to get the storage main folder.
If I'm not mistaken, the path which is provided should be the absolute filepath on your server. For example instead of:
$targetPath = 'public/uploads/'.$user_id;
Use (your actual path will vary depending on your configuration)
$targetPath = '/var/www/sitename/public/uploads/'.$user_id;
Laravel also contains a helper function called public_path() which can be used to obtain the "fully qualified path to the public directory". This would allow you to use something such as:
$targetPath = public_path('uploads/'. $user_id);
Also, on this line, do not forget to place a slash before the new filename:
$newImg = Image::make($targetPath . '/' . $newName);
I would also confirm that the user executing the script (if apache or nginx usually www-data unless altered) has write permissions to your public/uploads/ directory
Finally, I got it working. I made following changes to my code:
Use the full OS path as suggested by commanderZiltoid for the destination path.
Don't use Storage::putFileAs method to save the file. So, remove this line: Storage::putFileAs($targetPath, $file, $original);
Don't use Storage::copy() to copy the file, so, remove this line:
Storage::copy($targetPath . $original, $targetPath . $newName);
For points 2 and 3, use Image::make($file->getRealPath()); This will create the file and remember the path where the file was created. Image->resize method will use this path later.
In the end, save the relative path in the database, as here: $profile->img = 'storage/uploads/'.$user_id.'/img/profile/'.$fName. Since we'll use {{ asset($profile->img) }}, it's necessary to save only the relative path and not the absolute OS path.
if($request->hasFile('img')) {
if($request->file('img')->isValid()) {
$types = array('_original.', '_32.', '_64.', '_128.');
$sizes = array( array('32','32'), array('64','64'), array('128','128'));
$targetPath = '/Users/apple/Documents/_chayyo/chayyo/storage/app/public/uploads/'.$user_id.'/img/profile/';
try {
$file = $request->file('img');
$ext = $file->getClientOriginalExtension();
$fName = time();
$o_name = $fName . array_shift($types) . $ext;
$original = Image::make($file->getRealPath());
$original->save($targetPath . $o_name);
foreach ($types as $key => $type) {
$newName = $fName . $type . $ext;
$newImg = Image::make($file->getRealPath());
$newImg->resize($sizes[$key][0], $sizes[$key][1]);
$newImg->save($targetPath . $newName);
}
$profile->img = 'storage/uploads/'.$user_id.'/img/profile/'.$fName;
}
catch (Illuminate\Filesystem\FileNotFoundException $e) {
}
}
}

Resources