Laravel 5 on shared hosting - wrong public_path() - php

I deployed a Laravel 5 project to a shared hosting account, placing the app-files outside of the www-folder, placing only the public folder inside of the www-folder. All like explained here, in the best answer: Laravel 4 and the way to deploy app using FTP... without 3. because this file doesn't exist in Laravel 5.
Now when I call public_path() inside of a controller i get something like my-appfiles-outside-of-www/public instead of www/public. Does anyone know why I doesn't get the right path here? Can I change this somewhere?
Thanks!

You can override public_path using container.
Example:
App::bind('path.public', function() {
return base_path().'/public_html';
});

$app->bind('path.public', function() {
return __DIR__;
});
write above code in public_html\index.php above of this code
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

There are a number of solutions, like a change to index.php or the accepted one with the ioc container.
The solution that works best, in my opinion, is described in this SO question:
Laravel 5 change public_path()
Why is it better than other solutions? Because it works for regular http request, use of artisan ánd use of phpunit for testing! E.g. the change to index.php works only for http requests but leads to failures when using PHPunit (in my case: file (...) not defined in asset manifest).
A short recap of that solution:
Step 1: In the file: bootstrap/app.php change the very first declaration of $app variable from:
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
to:
$app = new App\Application(
realpath(__DIR__.'/../')
);
This points to your own custom Application class, which we will create in step 2.
Step 2: Create the file Application.php in the app folder:
<?php namespace App;
class Application extends \Illuminate\Foundation\Application
{
public function publicPath()
{
return $this->basePath . '/../public_html';
}
}
Be sure to change the path to your needs. The example assumes a directory structure like so:
°°laravel_app
°°°°app
°°°°bootstrap
°°°°config
°°°°...
°°public_html
In case of the OP, the path should probably be
return $this->basePath . '/../www/public';
(up one from laravel_app, then down into www/public)

Related

Controllers not working on Laravel 8 despite uncommenting in RouteServiceProvider

I try to create routes to my index.blade.php page, i've made a controller "ProductController" using cmd php artisan make:controller ProductController, so in http --> Controllers i do have a ProductController.php file and i put this code in it :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProductContoller extends Controller
{
public function index()
{
return view('products.index');
}
}
and then in my web.php i create a route using this code
Route::get('/boutique', 'ProductController#index');
However it doesn't work.
Firstly, when i go to the pretty url i've setup for my project at localhost using Laragon --> Projetname.test i get the normal Laravel Welcome page, but when i try to go to the url i've just setup like : ProjectName.test/boutique, i get
"Target class [App\Http\Controllers\ProductController] does not exist."
After reading about the changes since the update of Laravel to V8 here, i've seen that the update made some requirements for routes since $namespace prefix are not enabled automatically, but however that can be enabled again by uncommenting this line in RouteServiceProvider
// protected $namespace = 'App\\Http\\Controllers';
I do uncommenting that line and then clear the cache using php artisan route:cache, however it still not working..
When i first started doing research about routes issues in Laravel i've seen many forum spotted out that apache Allowoverride settings in httpd.config file may cause issue, so i change it settings from None to All and then restart Laragon but nothing works.
After correcting label on my controller it still do not work, i try both methode (the old and the new one) none of them works for me, cmd keeps returning me :
λ php artisan route:list
Illuminate\Contracts\Container\BindingResolutionException
Target class [ProductController] does not exist.
at C:\laragon\www\ProjectName\vendor\laravel\framework\src\Illuminate\Container\Container.php:835
831▕
832▕ try {
833▕ $reflector = new ReflectionClass($concrete);
834▕ } catch (ReflectionException $e) {
➜ 835▕ throw new BindingResolutionException("Target class [$concrete] does not exist.", 0, $e);
836▕ }
837▕
838▕ // If the type is not instantiable, the developer is attempting to resolve
839▕ // an abstract type such as an Interface or Abstract Class and there is
1 [internal]:0
Illuminate\Foundation\Console\RouteListCommand::Illuminate\Foundation\Console\{closure}(Object(Illuminate\Routing\Route))
2 C:\laragon\www\ProjectName\vendor\laravel\framework\src\Illuminate\Container\Container.php:833
ReflectionException::("Class "ProductController" does not exist")
Laravel 8 Route should be
Route::get('/boutique', [NameController:class,'method']);
So in your web.php file add
use App\Http\Controllers\ProductContoller
Then write your route like this:
Route::get('/boutique', [ProductContoller::class,'index']);
And I think there is a missing 'r' in your "ProductController" class name
I found out after watching a tutorial here on most common issues with new routing methodes on Laravel 8 that when uncommenting the RouteServiceProvider, using the old method require to use the old route method too on web.php, so it looks like that :
Route::get('/boutique', 'ProductController#index');
Please use
Route::get('/boutique', '\App\Http\Controllers\ProductController#index');
or use name route group and indicate the namespace
Route::group(['namespace' => 'App\Http\Controllers'], function(){
Route::get('/boutique', 'ProductController#index');
});
let me know how it works.

Laravel HTTP test to own API adds last part form APP_URL

Short:
I cannot test my own API, because of the current APP_URL environment variable that I am using.
APP_URL contains http://localhost:8080/foldername, whereas foldername is a random string character that is very important to our dev-environment. If I try to run the test from the snippet below, my backend recieves the path like foldername/api/users instead of api/users - Of course this will not work.
Problem: I cannot change the APP_URL inside the .env file, nor in the phpunit.xml file. I have to solve this programmatically. How can I cut this "foldername" off?
Long:
I wanted to test my own API that I've built in Laravel, but every test failed with "invalid JSON was returned from the route" - which is weird because I know that my API works. (requests with axios do return the correct json)
The test is very basic and looks like this:
namespace Tests\Feature;
use Tests\TestCase;
class UserTest extends TestCase {
public function test_get_users() {
$response = $this->json('GET', url('/api/users')); //falsely tests foldername/api/users
$response->assertJsonCount(1);
}
}
The routes are defined in the routes/api.php file:
Route::resource('users', 'UserController');
I decided to catch and dump the requested route in one of the used middlewares via $request->path()
and got the output mentioned above.
I first tried it without using the built-in url helper, but with even worse results - maybe these errors correlate, but I cannot see how.
$this->json('GET', '/api/users'); //received as '/' instead - no route at all
Adding this line to the phpunit.xml did not do anything, and even if it did, hardcoded "localhost:8080" won't do. We have many different systems with different app_urls, but every single one has a "foldername" at the end of it, which has to be ignored.
<server name="APP_URL" value="http://localhost:8080"/>
I altered APP_URL inside my .env file and cleared all caches, which made the tests work, but break the rest of the program.
We use Laravel 6.5 and php 7.4
Worked around the problem by overriding the setUp method:
namespace Tests\Feature;
use Tests\TestCase;
class UserTest extends TestCase {
use WithFaker;
public function setUp(): void {
parent::setUp();
\URL::forceRootUrl(dirname(env('APP_URL')));
}
public function test_create_user() {
$response = $this->json('GET', url('/api/users'));
// $response->assertJson(...);
}
}
I still do not understand why my backend gets requested with an empty route "/", when I pass the route how the documentation describes it:
$response = $this->json('GET', '/api/users');

PhalconPHP and phpunit

I've been following the docs to set up phpunit with phalcon. I have the example working.
However, I now want to actually put it to use and test my own classes, to do this I understand I need to register the directories in the loader, but instead of repeating the directories that are already defined in the config, I'm wanting to include the config in the php unit test helper class (from a `phalcon project' command). This sounds simple but is anything but.
Do I have to add additional code to access the $config?
Am I right in assuming that the docs are missing a large amount of code regarding testing your own classes, or, should it work straight out the box after following the docs?
I have tried to implement this myself the basic idea is below for an implementation example head to: https://github.com/SavvySoftWorksLLC/phalcon_3_2_devtools_sample_project/tree/pks/setup_phpunit
If you externalize your loader like
<?php
$loader = new \Phalcon\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->registerDirs(
[
$config->application->controllersDir,
$config->application->modelsDir
]
)->register();
And then call it in your entrypoint like this:
include ROOT_PATH . "/../app/config/loader.php";
You will be able to reuse the same loader in your test helper provided you initialize a fresh DI container like the docs mention.
To give the big picture I pushed up a out of the box app create by devtools for you to look at.
Loader: https://github.com/SavvySoftWorksLLC/phalcon_3_2_devtools_sample_project/blob/master/app/config/loader.php
EntryPoint:
https://github.com/SavvySoftWorksLLC/phalcon_3_2_devtools_sample_project/tree/master/public

PHP - Slim Framework: Best practice with a lot of code inside routes closures

I'm using Slim. In the documentation they only show examples working with only one index.php file, which has really little functionality for every route. For example:
$app = new \Slim\Slim();
$app->get('/books/:id', function ($id) {
//Show book identified by $id
});
But in my case, my index.php file is getting bigger and bigger, now I have a lot of code for most routes, what is the best practice in this case? to include files inside the routes closures? What happens with the scope of global variables, like DB connection or app config? Thank you
Brian Nesbitt made a nice post about this: http://nesbot.com/2012/11/5/lazy-loading-slim-controllers-using-pimple.
If you don't want to use pimple, than you can get some idea from the section "Common first attempt", on how to separate you files.
update:
Since version 2.4.0 you can use the inbuilt "Class controller": Version 2.4.0

How to get the server path to the web directory in Symfony2 from inside the controller?

The question is as follows:
How can I get the server path to the web directory in Symfony2 from inside the controller (or from anywhere else for that reason)
What I've already found (also, by searching here):
This is advised in the cookbook article on Doctrine file handling
$path = __DIR__ . '/../../../../web';
Found by searching around, only usable from inside the controller (or service with kernel injected):
$path = $this->get('kernel')->getRootDir() . '/../web';
So, is there absolutely no way to get at least that 'web' part of the path? What if I, for example, decided to rename it or move or something?
Everything was easy in the first symfony, when I could get like everything I needed from anywhere in the code by calling the static sfConfig::get() method..
There's actually no direct way to get path to webdir in Symfony2 as the framework is completely independent of the webdir.
You can use getRootDir() on instance of kernel class, just as you write. If you consider renaming /web dir in future, you should make it configurable. For example AsseticBundle has such an option in its DI configuration (see here and here).
To access the root directory from outside the controller you can simply inject %kernel.root_dir% as an argument in your services configuration.
service_name:
class: Namespace\Bundle\etc
arguments: ['%kernel.root_dir%']
Then you can get the web root in the class constructor:
public function __construct($rootDir)
{
$this->webRoot = realpath($rootDir . '/../web');
}
You also can get it from any ContainerAware (f.i. Controller) class from the request service:
If you are using apache as a webserver (I suppose for other
webservers the solution would be similar) and are using
virtualhosting (your urls look like this - localhost/app.php then you can use:
$container->get('request')->server->get('DOCUMENT_ROOT');
// in controller:
$this->getRequest()->server->get('DOCUMENT_ROOT');
Else (your urls look like this - localhost/path/to/Symfony/web/app.php:
$container->get('request')->getBasePath();
// in controller:
$this->getRequest()->getBasePath();
You are on Symfony, think "Dependency Injection" ^^
In all my SF project, I do in parameters.yml:
web_dir: "%kernel.root_dir%/../web"
So I can safely use this parameter within controller:
$this->getParameter('web_dir');
My solution is to add this code to the app.php
define('WEB_DIRECTORY', __DIR__);
The problem is that in command line code that uses the constant will break. You can also add the constant to app/console file and the other environment front controllers
Another solution may be add an static method at AppKernel that returns DIR.'/../web/'
So you can access everywhere
UPDATE: Since 2.8 this no longer works because assetic is no longer included by default. Although if you're using assetic this will work.
You can use the variable %assetic.write_to%.
$this->getParameter('assetic.write_to');
Since your assets depend on this variable to be dumped to your web directory, it's safe to assume and use to locate your web folder.
http://symfony.com/doc/current/reference/configuration/assetic.html
For Symfony3
In your controller try
$request->server->get('DOCUMENT_ROOT').$request->getBasePath()
$host = $request->server->get('HTTP_HOST');
$base = (!empty($request->server->get('BASE'))) ? $request->server->get('BASE') : '';
$getBaseUrl = $host.$base;
Since Symfony 3.3,
You can use %kernel.project_dir%/web/ instead of %kernel.root_dir%/../web/

Categories