0
votes

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

1

1 Answers

2
votes

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: