Laravel package migration class can not find sibling class - php

I'm creating a Laravel package.
This is my folder structure:
- host => (a laravel app to test the package)
- WebSite
- packages
- Company
- FirstPackage
- database
- migrations
- src
- Models
- Http
- Controllers
Inside migrations folder I have two migration classes:
2021-06-04-create-customers-table
2021-06-04-add-name-to-customers
Inside CreateCustomersTable class I have a constant called TABLE_NAME.
Inside AddNameToCustomers class I want to reuse that constant, and I simply use it like CreateCustomersTable::TABLE_NAME.
My IDE which is VS Code does not complain. But when I run php artisan migration, I get this error:
Class 'CreateCustomersTable' not found
at packages/Company/FirstPackage/database/migrations/2021-06-04-add-name-to-customers.php:line_number
Based on Laravel migrations: Class "not found", I made sure class names match file names, and I also tried to map classes in composer.json:
"autoload": {
"classmap": [
"database/migrations"
],
"psr-4": {
"Company\\FirstPackage\\": "src/"
}
},
But none of these values worked for me:
database/migrations
app/database/migrations
Company/FirstPackage/database/migrations
So I have two questions.
First: How can I fix this?
Second and more important: How should I debug class not found bugs?

Just use composer dumpautoload first, if it doesn't help follow below steps:)
First way: use a flag when executing migration commands.
This is inconvenient, but if you really need it, you can try:
php artisan migrate --path=/path/to/your/dir/with/migrations
Second way: you can add the paths that your migrations are in to your AppServiceProvider using $this->loadMigrationsFrom($paths);
How should I debug class not found bugs?
Check file name and class name;
Check the path where the class is located;
Run composer dumpautoload it can help you with warning messages like this
Class App\Namespace\To\Class\ClassName located in ./app/directory/to/class/ClassName.php does not comply with psr-4 autoloading standard. Skipping.;
And finally you can check vendor/composer/autoload_* files to find your mistakes.

Related

Use Models / Controllers from a sub directory in new project

So I've been asked to create a new project in Laravel (5.4). The project will need to load in a "platform" which is also built in Laravel 5.4 and contains already written controllers and models.
I am currently autoloading the platform in composer as so :
"psr-4": {
"App\\": "app/",
"Frontend\\": "app/Modules/Frontend/",
"Admin\\": "app/Modules/Admin/",
"Platform\\": "../platform/Modules/"
}
I have a routes file with the following in it :
Route::get('/', 'HomeController#index')->name('home');
Then inside of my HomeController, I'm trying to load the platforms' HomeController.
use Platform\Modules\Frontend\Controllers\HomeController as HC;
I am then presented with the error
Class 'Platform\Modules\Frontend\Controllers\HomeController' not found
Is this at all possible to do, wise to do? I'm open to any form of suggestions.
I have managed to mimic your situation in 2 PHP hello world projects.
The problem here is that your 2 projects are using the same namespace App and when you try to autoload the 2nd project into the namespace Platform, you get Class not found error. This is because your PSR-4 namespace for Platform doesn't correspond the namespace in your 2nd project.
App\Modules\Frontend\Controllers is never Platform\Modules\Frontend\Controllers. Those are totally 2 different namespaces.
Hopefully, there's a solution for this by providing an array of paths to the common namespace in both projects.
"psr-4": {
"App\\": ["app/", "../platform/Modules/"],
"Frontend\\": "app/Modules/Frontend/",
"Admin\\": "app/Modules/Admin/"
}
In your HomeController, load your controller like this:
use App\Modules\Frontend\Controllers as HC;
Always double check running the command below if you get Class not found error:
composer dump-autoload

Laravel package development - Target class [ControllerName] does not exist

I'm following a tutorial on how to create laravel packages.
I'm using Laravel v8.42.1 (PHP v7.4.3) and jetstream package.
I'm stuck on creating a controller for my package, I always get following error when trying to connect to my url via the laraval app (<base-url/playground):
Target class [TestVendor\TestPackage\Http\Controllers\PlaygroundController] does not exist.
The TestVendor\TestPackage\src\routes.php is recognized by the main application:
use TestVendor\TestPackage\Http\Controllers\PlaygroundController;
use Illuminate\Support\Facades\Route;
Route::get('/playground', [PlaygroundController::class, 'index']);
And is loaded from my ServiceProvider class:
$this->loadViewsFrom(__DIR__.'/resources/views', 'playground');
loadRoutesFrom(__DIR__.'/routes.php');
My namespacing is also normally correctly written in the composer.json of my package:
"autoload": {
"psr-4": {
"TestVendor\\TestPackage\\": "src/"
}
},
And I have my PlaygroundController in src/Http/Controllers/PlaygroundController.php:
namespace TestVendor\TestPackage\Http\Controllers;
use Illuminate\Routing\Controller;
class PlaygroundController extends Controller
{
public function index()
{
return view('playground::hello');
}
}
The view is also in the right package.
I'm using https://github.com/Jeroen-G/laravel-packager to scaffold my packages.
Did multiple composer auto-load and composer updates.
It seems my controller is not recognized in the main application, I think somewhere my name spacing is not correct?
I already had a look at:
Target class controller does not exist - Laravel 8
Solution did not work
Target class does not exist. problem in laravel 8
Solution did not work
You have namespaced your controller as:
namespace TestVendor\TestPackage\Http\Controllers;
In the line above though you say:
And I have my PlaygroundController in src/Http/PlaygroundController.php:
Unless that is a typo, you need to add a Controllers directory underneath Http and put your PlaygroundController in there:
src/Http/Controllers/PlaygroundController.php
For psr-4 autoloading, your folder structure and namespaces should mimic each other.

Composer class not found even if it exists

I'm developing a Laravel package but I have a problem with composer autoloading.
My package has 2 folders under src folder. One of them is named Laravel and the other one is Telegram. Here is the package structure:
./packages
.../typhoon
...../src
......./Laravel
........./Providers
............LumenServiceProvider.php
............LaravelServiceProvider.php
......./Telegram
..........Api.php
.....composer.json
This package is developed under SaliBhdr/Typhoon namespace.
I have added the packages/typhoon/src directory in Laravel's composer file like so:
"autoload": {
"psr-4": {
"App\\": "app/",
"SaliBhdr\\Typhoon\\" : "packages/typhoon/src/"
}
},
And add the src/ address in package composer.json file like so:
"autoload": {
"psr-4": {
"SaliBhdr\\Typhoon\\": "src/"
}
},
Here is the strange behavior begins. When I execute the php artisan serve command Laravel throws an error that says :
Class 'Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider' not found
And if I check if the class exists with class_exists('Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider') function it returns false. But if I check if Salibhdr\Typhoon\Telegram\Api exists it returns true.
I checked the autoload_classmap file and notice that the composer includes all the classes under Telegram subfolder but not Laravel subfolder.
Why composer acts weird like this? why did it include one subfolder and not the other? It is something that I do every day and never seen anything like this.
I desperately need help. Any help would be appreciated
You are trying to initialize Salibhdr\Typhoon\Laravel\Providers\LumenServiceProvider but in your composer it's "SaliBhdr\\Typhoon\\": "src/".
Notice the capital B in your composer. PHP classes are case sensitive so you have to make sure it's either both lowercase or both uppercase.
Also make sure to run composer dumpautoload if you modify composer.json.

Composer autoload files without running a command each time

This is a general question I have out of curiosity and might lead to something useful in projects of mine.
Every time I add a new file (for example a new controller or model) I have to run composer dump-autoload -o for it to include the file, not sure if i'm just doing something wrong or if that is how it works.
Is it possible for me to get composer to see the file automatically after I created the file with its contents?
My first thought was to just create a script to run the command in either a special "refresh" file but that seems to be a waste.
I am using PSR-4 to load my files.
composer.json autoload:
"autoload":{
"psr-4":{
"Website\\":"app"
}
},
You need to configure your composer.json file so that the autoloader knows where to look for specific namespaces:
"autoload": {
"psr-4": {
"App\\": "src/"
},
"files": [
"src/simpleFunctions.php"
]
}
After running composer update, the autoloader will know where to look when a script encounters a namespace that falls under these definitions automatically, without any further command to write.
You have to respect the file hierarchy and psr-4 while naming and creating your classes. In the example above, adding a App\Controller\MyController class is straightforward, you add it in the Controller folder and it will be autoloaded on your next run.
/src
/Controller
MyController.php
/Model
/Mappers
MyMapper.php
simpleFunctions.php
namespace App\Controller;
class MyController {}
Casing is important!
When seeing a namespace like Website\Controllers, the autoloader will look for there files, under the root for the namespace specified, with the same casing. That means, that if you are under a case sensitive system (like Linux distributions) you actually need to respect the case. In your case the class Website\Controllers\Front must be in app/Website/Controllers/Front.php.
Basically, Composer doesn't aware of files that you are creating, you have to run the dump-autoload command which won't download anything new. It just regenerates the list of all classes that need to be included in the project (autoload_classmap.php). Ideal for when you have a new class inside your project.
Ideally, we execute composer dump-autoload -o , for a faster load of your webpages. The only reason it is not default, is because it takes a bit longer to generate (but is only slightly noticeable)

Including my class in a Laravel 5 Project

I made a class in php with some helper methods that parse HTML files.
I'd like to use this class in my Laravel project, but I'm new to Laravel and it's not clear how to add a simple class to a Laravel 5 project.
Is this possible? Or do I need to go to all the trouble of creating a composer package for my class, hosting it somewhere, and then require it in my composer.json file. That seems like a lot of work for including a simple PHP class, and I'm hoping there's an easier way.
As it stands right now there's not a great/easy way to do this in Laravel 5 (possibly by design). The two approaches you can take are
Create a new class in the App namespace
By default Laravel 5.0 looks for App\ prefixed classes in the app/ folder, so something like this should work
#File: app/Helpers/Myclass.php
<?php
namespace App\Helpers;
class Myclass
{
}
and then create your class with
$object = new App\Helpers\Myclass;
This approach, however, relies on you creating classes in the App\ namespace, and there's some ambiguity around if the App\ namespace is owned by Laravel, or is owned by the developer of the application.
Create your own Namespace and Register as PSR-4 autoloader
A better, but more complicated, approach would be to create classes in your own namespace, and then tell Laravel about this namespace by registering a new PSR autoloader.
First, you'd create the class definition
#File: application-lib/Myclass.php
<?php
namespace Pulsestorm;
class Myclass
{
}
Notice we've created a new folder off the root folder to hold our classes named application-lib. You could name this folder anything you like, because in the next step, you're going to add a section to your composer.json file's autoloader section
#File: composer.json
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/",
"Pulsestorm\\": "application-lib/"
}
},
The section we've added is this
"Pulsestorm\\": "application-lib/"
The key to the object (Pulsestorm\) is your namespace. The value (application-lib) is the folder where composer should look for class definition files with the specified namespace.
Once you've added this to composer.json, you'll need to tell Composer to regenerate it's autoload cache files with the dumpautoload command
$ composer dumpautoload
Generating autoload files
After doing the above, you should be able to instantiate your class with
$object = new Pulsestorm\Myclass;
The "real" right way to do this would be to create a generic composer package for your helper class, and then require that composer package into your laravel project. That may, however, be more work than you care to take on for a simple library helper.
If your class is generic enough to use it in other projects, the best way is to release it as a package.
Here's how you create packages with Laravel 5: http://laravel.com/docs/5.0/packages

Categories