I'm trying to namespace my Models in Laravel, and also have them be autoloaded automagically like the normal models do in the root of app/models. composer dump-autoload works, but I don't want to run that after I create a new model.
#app/models/MyNamespace/Thing.php
<?php
namespace App\Models\MyNamespace;
class Thing {
// ...
}
#app/routes.php
<?php
Route::get('test', function(){
$thing = new App\Models\MyNamespace\Thing;
});
If I run composer dump-autoload everything is fine, otherwise I get a class not found exception.
What can I do to make that kind of structure work without rebuilding the classmap every time I make a new class? I think PSR-0 is where your namespaces correlate directly with your directory structure, and it appears as though my classes are adhering to that...
I've also tried using the Workbench which works great, but ideally I'd like to have, for ex: app/models/MyNamespace, app/models/AnotherNamespace.
This is not a Laravel 'problem', this is something that will work, exactly the same way, on every application that uses Composer.
If your classes are following the psr-0 rules (directory structure matters!), you can configure it in your composer.json
{
"autoload": {
"psr-0": {"MyNamespace\\": "app/models"}
}
}
Execute
composer dump-autoload
Once and it it will show in your autoload_namespaces.php. After that Composer will be able to find your classes by its namespaces, no need to dump-autoload again.
To explain better how it works. If you do
"psr-0": {"MyNamespace\\": "app/models"}
You must use it this way:
$user = new MyNamespace\User.php
Because Composer adds your namespace to the end of your namespace path and it will expect to find User.php in
/var/www/yourappdir/app/models/MyNamespace/User.php
So, by doing
"psr-0": { "App\\Models\\": "" }
You are telling Composer that ALL /var/www/yourappdir/App/Models subfolders can contain namespaced files of the App\Models namespace. And you'll be able to address files like:
$user = new App\Models\User.php
$user = new App\Models\MyNamespace\User.php
$user = new App\Models\MyNamespace\Foo\Bar\User.php
And if you do
"psr-0": { "App\\Foo": "" }
Composer will be able to address those namespaces
/var/www/yourappdir/App/Foo
/var/www/yourappdir/App/FooBar
/var/www/yourappdir/App/Foo/Bar
/var/www/yourappdir/App/Foo/Bar/Baz
But if you do
"psr-0": { "App\\Foo\\": "" }
It will be able to address just
/var/www/yourappdir/App/Foo
/var/www/yourappdir/App/Foo/Bar
/var/www/yourappdir/App/Foo/Bar/Baz
Related
I'm trying to build a site with slim and autoloading my controller classes for the routes. I'm currently setting up the base structure and testing with a single route with nothing more than a simple "Test" output.
I prevously did this stuff with defining a spl_autoload_register function, but as this approach isn't recommended by slim and composer I want to do it right and I'm not trying to autoload my classes.
My Project is set up as this:
The class BlockController inside the file with the same Name under Controller is inside a namespace defined with namespace MyAPI\Controller;
app/Controller/BlockController.php
namespace MyAPI\Controller;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class BlockController
{
public function getList(Request $request, Response $response, $args)
{
return $response->withStatus(200)
->withHeader('Content-Type', 'text/html')
->write("Test");
}
}
I'm loading the dependencies and settings and after that all my routes (which contains currently only some small ones for testing my architecture):
public/index.php:
require __DIR__ . '/../vendor/autoload.php';
$settings = require __DIR__ . '/../app/settings.php';
$app = new \Slim\App($settings);
require __DIR__ . '/../app/dependencies.php';
require __DIR__ . '/../app/routes.php';
$app->run();
app/routes.php (is very simple, will be extended with more Route-files):
require 'Routes/BlockRoute.php';
app/Routes/BlockRoute.php:
use MyAPI\Controller\BlockController;
$container["BlockController"] = function ($container) {
return new BlockController($container);
};
$app->group('/block', function() use ($container) {
$this->get('[/]', 'BlockController::getList');
});
So the first command inside BlockRoute.php is the use of the BlockController-namespace. Everything under app/ should have the Base-Namespace MyAPI.
As described in the slim-documentation I planned to do that with to autoload feature of composer, so I modified my composer.json and added the following:
{
"require": { .. },
"autoload": {
"psr-4": {
"MyAPI\\": "app"
}
}
}
Edit: updated path to app-folder after the answer from Adam Lavin
After that I ran composer update. Is that the right command for those changes? Or should I use composer install? Couldn't find any more information what I have to do after making those additions in the autoload-section.
When I run the site now with the php webserver and navigate to this route /block I get the following RuntimeException:
Callable BlockController::getList does not exist
File: C:\Prog\src\vendor\slim\slim\Slim\CallableResolver.php
So the problem is that BlockController doesn't get included/autoloaded correctly but I don't understand why or what exactly the problem is. I tried to find some examples of working configurations with slim+composer+autoloading of classes but couldn't find something related.
Any input appreciated.
Since you're pointing MyApp\\ to ../src (the same directory as composer), the autoloader is going to try and find the controller in src/Controllers/BlockController.php.
It should be pointing to ../src/app, though since composer.json is in the src folder it can be simplified to app in the resulting composer.json file.
{
"require": { .. },
"autoload": {
"psr-4": {
"MyAPI\\": "app"
}
}
}
Additionally, In your example, the namespace of the BlockController is MoinAPI\Controllers, and should be MyAPI\Controllers.
And finally, in slim, you use a single colon instead of a double to refer to a callable route. BlockController::getList should be BlockController:getList
Run this from within docker container, or using the same php binary that composer used.
composer dump-autoload -o -vvv #-o fixed my problem in my case
So I've been trying to create a custom class file for all my custom classes and append them in there, I'm using namespaces in order to accomplish using them in my controller however the controller is not recognizing the class
Ok:
Here is my custom class file placed in my project as app/Library/robloxClasses.php
namespace App\Library;
class RobloxMaths{
public function sortArrayOfArray(&$array, $subfield)
{
$sortarray = array();
foreach ($array as $key => $row)
{
$sortarray[$key] = $row[$subfield];
}
array_multisort($sortarray, SORT_DESC, $array);
}
}
Library is a folder i made to store all my custom class files in there
Here is how my controller ApiController uses the file using it's namespace
<?php
namespace App\Http\Controllers;
use App\Library\RobloxMaths;
use Illuminate\Http\Request;
class ApiController extends Controller
{
protected $RobloxClass;
public function __construct(){
$this->$RobloxClass= new RobloxMaths;
}
}
?>
The problem is, it keeps returning:
Class 'App\Library\RobloxMaths' not found
And I honestly do not know what's wrong, please help!
NOTE: I have tried composer update, and it fixes it temporarily but after a day or two or after me installing new dependencies it notifies me that the Class 'App\Library\RobloxMaths' not found thing happened
help please
Ensure that you have correctly setup the psr-4 autoload root in your composer.json file and that your file/directory names match perfectly including capitalisation, then run composer dump-autoload.
Example:
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
This will assign the root namespace App to the app folder.
If you are using an IDE, there is a large chance that your use and namespace statements where auto-generated with the lowercase app to match the directory name. As all the names tie up correctly in the IDE there are no errors, but when it comes to running the PHP script the autoloader is not doing require|require_once on your files and therefore your classes are not available.
Option 1 (Do this)
Ensure that your namespaces have consistent capitalisation that matches the composer.json entry.
Option 2 (Written for completion)
Ensure that you add a new entry for this root namespace to your composer.json file. For the example above this would be:
"autoload": {
"psr-4": {
"App\\": "app/",
"app\\": "app/"
}
}
It's an old question, but I had the same problem with laravel 9,
The problem is that I've used php short tag <? instead of <?php at the custom class file.
it's silly but this was the solution for me.
I'm trying to figure out how to get composer to look for classes for a specific namespace under 2 directories. What I'm thinking of is this:
Default location: /src/MyModule/myClass.php
Override location: /config/override/MyModule/myClass.php
Now, I'd like to use composer to configure the autoloader to check if a class exists under the Override location. If it does, use this class. If not, load the class from the default location.
Is this possible using composer or would I have to implement this logic using my own autoloader?
From Composer documentation:
If you need to search for a same prefix in multiple directories, you
can specify them as an array as such:
{
"autoload": {
"psr-4": { "Monolog\\": ["src/", "lib/"] }
}
}
You would add that to your composer.json file of course. To do it programatically you can do this:
$autoloader = require __DIR__.'/../vendor/autoload.php';
$autoloader->addPsr4('MyModule\\', [ '/first/dir/MyModule', '/another/dir/MyModule' ]);
I want to add Accessors and Mutators to a model. In Laravel 4 it worked all fine, but with Laravel 5 I have some trouble.
I have a "lib" folder in my App directory which contains the "db_transformers.php" file. This file holds classes like "dbDate" with a set and get function to transform dates stored in the database to a user-friendly format.
The "db_transformers.php" file is namespaced:
<?php namespace App\lib;
I also rerfer to the folder in my model:
use App\lib;
But my methodes still throw errors:
public function getDateTimeAttribute($value)
{
return dbDate::get($value);
}
This will return a "Class 'App\dbDate' not found" error.
What could be my problem?
You're confusing autoloading (PHP including/requiring a class definition file) with namespaces (a system that allows hierarchical naming of PHP classes/functions to help prevent code conflicts).
It's an easy thing to do. Covering the changes to autoloading in Laravel 5 is beyond the scope of a Stack Overflow question, but if you're interested I've written a multiple article series on how autoloading works with composer/Laravel 4/Laravel 5.
To your specific question, you say you've defined a class named dbDate in a file named db_transformers.php, and db_transformers.php has a namespace of App\lib.
#File: lib/db_transformers.php
namespace App\lib;
//other code
class dbDate
{
//other code
}
//other code
This mean your class's full name is App\lib\dbDate. The entire thing is the class's name. That's probably the biggest thing to get used to with namespaces in PHP.
This means if you wanted to use the class in other code, you'd need to refer to the full class name, including a leading backslash.
return \App\lib\DbDate::get($value);
You could also import the class using the use keyword
use App\lib\DbDate;
//other code
public function getDateTimeAttribute($value)
{
//since we imported the class with `use`, we don't need to type the full name
return DbDate::get($value);
}
The use keywords imports a specific class into the current namespace. When you said
use App\lib;
you were telling PHP
You know that global classApp\lib? I'm going to refer to it below as lib
Since you don't have a class named lib, this is meaningless, and it's why your use didn't help.
So that's namespaces. The other problem you need to solve is autoloading. Autoloading is what lets you skip the require or include statement/function when you want a class definition files in your project.
Laravel 4 used a bunch of different autoloaders, including something called a classmap autoloader. The classmap autoloader automatically parses all the files in your project looking for classes, and creates a giant map of which class is where (that's over simplifying it a bit, see the article series I linked earlier for the full details).
In Laravel 4, the classmap autoloader probably read the file in lib for you. Laravel 5 reduced the number of autoloaders, which included getting rid of the classmap autoloader for most folders.
The simplest thing you can do in Laravel 5 is to configure your project to use the classmap autoloader again. Open up composer.json and find this section
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
}
},
And add lib to the classmap autoloader section
"autoload": {
"classmap": [
"database",
"lib"
],
"psr-4": {
"App\\": "app/"
}
},
This tells composer to include the lib folders when it creates its autoloader files. You'll need to run the dumpautoload command
composer dump-autoload
after doing that, and you should be able to use the classes defined in lib/db_transformers.php as you wish.
You need to use the complete class name: use App\lib\dbDate;
You might also look into using view decorators for this purpose, as doing it in your model is really not appropriate.
Several packages exist to help with this, e.g. https://github.com/ShawnMcCool/laravel-auto-presenter
I'm using the Laravel framework and have a directory of the following structure:
models
Statistic.php
presenters
StatisticPresenter.php
In my models/Statistic class, I'm trying to access a present method which calls a protected property which then references my presenter:
protected $presenter = 'presenters\StatisticPresenter';
public function present() {
return new $this->presenter($this);
}
Yet, this returns the error: Class 'presenters\StatisticPresenter' not found. I realize this is a namespacing error of some sort, and I've tried watching a few videos on how it works, but I simply can't wrap my head around it. I have already added my presenter folder to my composer.json file. For example, adding this to the top of my Statistic model does not work:
use presenters\StatisticPresenter;
How can I fix this?
Do the followings;
Mark your namespace in StatisticPresenter.php ? (at the top of file "namespace presenters;")
Add PSR-4 class map to your composer
{
"autoload": {
"psr-4": {
"presenters\\": "app/presenters/"
}
}
}
run "composer dump-autoload" once and you wont need to run this command again for the "presenters" namespace if you add new classes into "app/presenters/ folder"
Test your class with "use presenters/StatisticPresenter;"
If you can access your class you dont need to change your code your present() function will be valid