The code below is me attempting to load Mustache into a Composer library (meaning the library itself is also being loaded by composer by the full project) I'm making for a project.
<?php
namespace TradeDefender\SiteEngine;
require '../../vendor/autoload.php';
class MessageEngine{
function test(){
$m = new Mustache_Engine;
return "hello";
}
}
?>
The directory structure for the library itself looks like this:
.
├── lib
│ └── TradeDefender
│ ├── Api
│ ├── Conn
│ └── SiteEngine
└── vendor
├── composer
└── mustache
I'm suspecting that it's due to me setting a namespace in the class, but I'm not sure how to fix it. The error itself is that it's not able to find the Class Mustache_Engine in the SiteEngine folder. The autoloader itself is being loaded just fine.
Any ideas? Thanks.
The problem was that I was loading the Mustache_Engine from the locally defined namespace rather than the global namespace. To load from the global namespace I had to put a \ infront of Mustache_Engine, like so:
$m = new \Mustache_Engine;
Related
I am creating a PHP project and want to implement PSR-4 autoloading.
I don't know which files I need to create in the vendor directory to implement autoloading for class files.
If you are using composer, you do not create the autoloader but let composer do its job and create it for you.
The only thing you need to do is create the appropriate configuration on composer.json and execute composer dump-autoload.
E.g.:
{
"autoload": {
"psr-4": {"App\\": "src/"}
}
}
By doing the above, if you have a file structure like this
├── src/
│ ├── Controller/
│ ├── Model/
│ ├── View/
│ └── Kernel.php
├── public/
│ └── index.php
└── vendor/
After executing composer dump-autoload the autoloader will be generated on vendor/autoload.php.
All your classes should be nested inside the App namespace, and you should put only one class per file.
E.g.:
<?php /* src/Controller/Home.php */
namespace App\Controller;
class Home { /* implementation */ }
And you need only to include the autoloader in your entry-point script (e.g. index.php).
<?php
require '../vendor/autoload.php';
Which will allow you to simply load your classes directly from anywhere after this point, like this:
use App\Controller\Home;
$homeController = new Home();
This is explained at the docs, here.
I am creating a PHP project and want to implement PSR-4 autoloading.
I don't know which files I need to create in the vendor directory to implement autoloading for class files.
If you are using composer, you do not create the autoloader but let composer do its job and create it for you.
The only thing you need to do is create the appropriate configuration on composer.json and execute composer dump-autoload.
E.g.:
{
"autoload": {
"psr-4": {"App\\": "src/"}
}
}
By doing the above, if you have a file structure like this
├── src/
│ ├── Controller/
│ ├── Model/
│ ├── View/
│ └── Kernel.php
├── public/
│ └── index.php
└── vendor/
After executing composer dump-autoload the autoloader will be generated on vendor/autoload.php.
All your classes should be nested inside the App namespace, and you should put only one class per file.
E.g.:
<?php /* src/Controller/Home.php */
namespace App\Controller;
class Home { /* implementation */ }
And you need only to include the autoloader in your entry-point script (e.g. index.php).
<?php
require '../vendor/autoload.php';
Which will allow you to simply load your classes directly from anywhere after this point, like this:
use App\Controller\Home;
$homeController = new Home();
This is explained at the docs, here.
In Laravel 5 I'd like to change the default directory structure, so the path for app I want to move it to something like api, how can I accomplish this?
Example, instead of this structure:
.
├── app
├── bootstrap
├── config
├── database
├── public
├── resources
├── storage
├── tests
└── vendor
I want this:
.
├── api
├── bootstrap
├── config
├── database
├── public
├── resources
├── storage
├── tests
└── vendor
In my composer I've changed the namespace like so, as following this question: How to change app folder name in laravel 5:
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"Api\\": "api/"
}
},
But I'm getting the error:
[RuntimeException]
Unable to detect application namespace.
Well, after a while I found a way to accomplish this, after look around for other answers like this I figured out that the app path is hardcoded in Application::path() see the source
Then I could make it work by overriding the Application::path() method:
class Application extends \Illuminate\Foundation\Application
{
/**
* Overrides the path to the application "app" directory.
*
* #return string
*/
public function path()
{
return $this->basePath.DIRECTORY_SEPARATOR.'api';
}
}
Then update the bootstrap/app.php:
// Overrides the PATH to use api instead of app
$app = new Api\Application(
realpath(__DIR__.'/../')
);
Now I can have the following structure:
.
├── api
├── bootstrap
├── config
├── database
├── public
├── resources
├── storage
├── tests
└── vendor
A similar method was found in https://mattstauffer.co/blog/extending-laravels-application
In Laravel 5.7 you can now use $app->setAppPath($path), like so:
$app->useAppPath(realpath(__DIR__ . '/../api'));
This can be called from bootstrap/app.php.
I'm having no end of trouble with setting up class auto-loading with Composer, I've read and watched millions of reference materials at this point & somehow I appear to still be missing something crucial.
Some quick version information:
PHP - v5.6.17
Composer - v1.0-dev (alpha11, global install)
PHPUnit - v4.2.6
Temperament - frustrated
The project layout is relatively simple:
.
├── composer.json
├── framework
│ ├── classes
│ │ ├── Test1.php
│ ├── config
│ │ ├── Test2.php
│ ├── financial.html
│ ├── form.html
│ ├── index.php
│ ├── models
│ │ ├── Base.php
│ ├── sample.html
│ └── services
│ └── validate.service.php
├── phpunit.xml
├── test
│ └── FormTest.php
└── vendor
├── autoload.php
├── composer
│ ├── autoload_classmap.php
│ ├── autoload_files.php
│ ├── autoload_namespaces.php
│ ├── autoload_psr4.php
│ ├── autoload_real.php
│ ├── ClassLoader.php
│ ├── installed.json
│ └── LICENSE
└── constants.php
"composer.json" currently contains the following:
{
"name": "testframework",
"require": {
"PHP": ">=5.6.17"
},
"autoload": {
"psr-4": {
"Config\\": "framework/config/",
"Classes\\": "framework/classes/",
"Models\\": "framework/models/"
},
"files": [
"vendor/constants.php"
]
}
}
Whenever I make changes to the directory structure, rename classes or modify "composer.json" I run:
% composer validate (only when modifying "composer.json")
% composer dump-autoload -o
I'm aiming to auto-load all classes from the "classes", "config" and "models" folders within "framework"; "index.php" currently implements "framework/models/Base.php", this is shown below.
<?php
require_once( dirname( __DIR__ ) . '/vendor/autoload.php' );
use Models\Base;
$derp = new BaseModel();
?>
I've verified that the above points to the correct location & returns: "/var/www/testproject/vendor/autoload.php"
Base.php contains the following script:
<?php namespace Models;
class BaseModel {
public $submitAction = null;
protected $complete;
public function __construct() {}
/**
* Expose
* Exposes the error code names for external processing.
*
* #return An array containing all error code names in this object.
*/
public static function Expose() {
$reflector = new ReflectionClass( 'ErrorCodes' );
return $reflector->getConstants();
}
}
I've gone through every permutation of the namespacing I can think of, have been endlessly modifying the "composer.json", adding and removing segments as per the documentation, working purely with classmap (which didn't work), testing "PSR-0" (also didn't work), using a bigger hammer (also didn't work).
Obviously I'm doing something horrifically wrong, I just don't seem to be able to puzzle out what; can anyone see where I'm going astray?
Many thanks,
N00b
Edit: Huge oversight, the "vendor/composer" directory contains the following relating to Composer's auto-loading.
"autoload_classmap.php":
<?php
// autoload_classmap.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Models\\BaseModel' => $baseDir . '/framework/models/Base.php',
);
"autoload_files.php":
<?php
// autoload_files.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'a9da57e70f975fe4a3c7dad63939dcd8' => $vendorDir . '/constants.php',
);
and "autoload_psr4.php":
<?php
// autoload_psr4.php #generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Models\\' => array($baseDir . '/framework/models'),
'Config\\' => array($baseDir . '/framework/config'),
'Classes\\' => array($baseDir . '/framework/classes'),
);
The errors I'm seeing are, from PHP:
Fatal error: Class 'BaseModel' not found in
/var/www/testproject/framework/index.php on line 8
and from PHPUnit:
user% phpunit
PHPUnit 4.2.6 by Sebastian Bergmann.
Configuration read from /var/www/testproject/phpunit.xml
PHP Fatal error: Class 'BaseModel' not found in
/var/www/testproject/test/FormTest.php on line 6
In your index.php you're not importing the right class:
use Models\Base;
$derp = new BaseModel();
You should import the Models\BaseModel class:
use Models\BaseModel;
$derp = new BaseModel();
Also, the file name should match the class name. The BaseModel class should be located in the framework/models/BaseModel.php file instead of framework/models/Base.php.
Note that you don't need to optimise the autoloader during development (that's what -o flag is doing). Only use it in production, otherwise you'll have to dump the autoloader each time you add a new class.
More about the autoloading standards can be read here:
http://www.php-fig.org/psr/psr-4/
http://www.php-fig.org/psr/psr-0/
I am trying to put all the peaces together I found about autoloading a class in composer but I can't make it work. Every example I see is missing some part. Basically it comes down to two files with 4 lines:
index.php
$loader = require 'vendor/autoload.php';
$loader->add('Vendor\\', __DIR__.'/../app/');
new Vendor_Package_Obj();
app/Vendor/Package/Obj.php
class Obj {}
I also tried psr-4 and all thinkable combinations of folders and names for `Vendor Package Obj? but no luck finding a working solution.
How can I autoload a file with composer using any of those standards?
According to PSR-4, The fully qualified class name MUST have a top-level namespace name, also known as a "vendor namespace" and underscores have no special meaning in any portion of the fully qualified class name.
Try this:
cd ~
mkdir -p testproj/src/MyApp/Package
cd testproj
composer init && composer update
Create your index.php with this content:
<?php
$loader = require 'vendor/autoload.php';
$loader->add('MyApp\\', __DIR__.'/src/');
$a = new MyApp\Package\Obj();
var_dump($a);
And put the Obj class (src/MyApp/Package/Obj.php) :
<?php
namespace MyApp\Package;
class Obj
{}
Now when you run the code:
php index.php
You should get this as output:
class MyApp\Package\Obj#2 (0) {
}
Also directory scaffolding should look like this:
testproj
├── composer.json
├── index.php
├── src
│ └── MyApp
│ └── Package
│ └── Obj.php
└── vendor
├── autoload.php
└── composer
├── ClassLoader.php
├── autoload_classmap.php
├── autoload_namespaces.php
├── autoload_psr4.php
└── autoload_real.php