Composer Auto-loading & PHPUnit - 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/

Related

Composer autoloader doesn't load class when I use variable

I've used autoloader from composer. Everything is fine when I set class name directly
<?php
namespace Matrix;
$router = new Router;
$object = $router->object;
$method = $router->method;
$id = $router->id;
$action = new Accounts();
It works. But if I try to set variable as a class name
$action = new $object();
it returns Fatal error: Uncaught Error: Class 'Accounts' not found.
var_dump($action);
returns string 'Accounts' (length=8)
Section autoload in my composer.json:
"autoload": {
"psr-4": {
"Matrix\\": "matrix/controllers/"
}
My directories structure:
├── matrix
│   ├── controllers
│   │   ├── Accounts.php
│   │   ├── BaseController.php
│   │   ├── OffersController.php
│   │   ├── RefreshController.php
│   │   └── Router.php
│   ├── index.php

How to change the app path to api in Laravel 5 directory structure

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.

Issue starting with Slim 2

I'm developing a web service using Slim Framework 2, it's the first time I use php. I'm having an issue with the Slim object:
There's my code:
require 'db.php';
require 'vendor/slim/slim/Slim/Slim.php';
echo 'require ok';
$app = new vendor/slim/slim/Slim();
echo '$app ok';
The 'require' lines are ok. But he $app line doesn't work I use the same path to the Slim.php file and also I've tryed to use this path:
$app = /slim/Slim();
The first echo is executing but the second one is not working. My ws.php file is on the same directori as the vendor folder:
vendor/slim/slim/Slim/
├── Environment.php
├── Exception
│   ├── Pass.php
│   └── Stop.php
├── Helper
│   └── Set.php
├── Http
│   ├── Cookies.php
│   ├── Headers.php
│   ├── Request.php
│   ├── Response.php
│   └── Util.php
├── Log.php
├── LogWriter.php
├── Middleware
│   ├── ContentTypes.php
│   ├── Flash.php
│   ├── MethodOverride.php
│   ├── PrettyExceptions.php
│   └── SessionCookie.php
├── Middleware.php
├── Route.php
├── Router.php
├── Slim.php
└── View.php
Is $app = new vendor/slim/slim/Slim(); correct? I'm lost about this topic.
Solved using Frank Martin solution:
require 'vendor/autoload.php';
$app = new \Slim\App;
Instead:
require 'vendor/slim/slim/Slim/Slim.php';
$app = new vendor/slim/slim/Slim();
Regards
Make sure you've installed the composer dependencies then use this instead.
require 'vendor/autoload.php';
$app = new \Slim\App;

Mustache_Engine not loading, conflict due to setting namespace?

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;

Composer autoload full example?

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

Categories