I am very new to Zend Framework 2 and am using the book “Web Development with Zend Framework 2” by Michael Romer as my guide. I’m at the end of chapter 5 and the subject of the ClassMapAutoloader is presented. The conclusion of the discussion is that my Helloworld module now has the file and directory structure of ->
Module.php
autoload_classmap.php
autoload_function.php
autoload_register.php
config/
module.config.php
public/
images/
css/
js/
src/
Helloworld/
Controller/
IndexController.php
views/
Helloworld/
Index/
index.phtml
As far as I can tell the files of interest that setup Classmap autoloading are Module.php, autoload_classmap.php, autoload_function.php, autoload_register.php. The contents of these files are
Module.php ->
<?php
namespace Helloworld;
Class Module {
public function getAutoloaderConfig() {
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php'
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__
)
)
);
}
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
}
autoload_function.php ->
<?php
return function ($class) {
static $classmap = null;
if ($classmap === null) {
$classmap = include __DIR_ . '/autoload_classmap.php';
}
if (!isset($classmap[$class])) {
return false;
}
return include_once $classmap[$class];
};
autoload_register.php ->
<?php
spl_autoload_register(include __DIR__ . '/autoload_function.php');
autoload_classmap.php ->
<?php
//require_once 'autoload_register.php';
return array();
This all works when I have that blank array return in autoload_classmap.php BUT in the book the example has require_once 'autoload_register.php';. When I uncomment that line I get the following error ->
The error is -> [Tue Jun 18 16:29:20 2013] [error] [client 199.82.163.121] PHP Fatal error: Uncaught exception 'Zend\Loader\Exception\InvalidArgumentException' with message 'Map file provided does not return a map. Map file: "/var/www/ZendApp/module/Helloworld/autoload_classmap.php"' in /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php:88\nStack trace:\n#0 /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php(117): Zend\Loader\ClassMapAutoloader->registerAutoloadMap('/var/www/ZendAp...')\n#1 /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php(60): Zend\Loader\ClassMapAutoloader->registerAutoloadMaps(Array)\n#2 /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php(46): Zend\Loader\ClassMapAutoloader->setOptions(Array)\n#3 /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/AutoloaderFactory.php(100): Zend\Loader\ClassMapAutoloader->__construct(Array)\n#4 /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/M in /var/www/ZendApp/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php on line 88
I know that returning the blank array causes the getAutoloaderConfig() in the Module class of Module.php to default to the StandardAutoloader and thus it works but Why? I’d really like to get the ClassMapAutoloader to do its thing in this example. How do I get this to work? Thanks in advance for your reply.
James Eastman
There is no such thing as requiring the autoloader register function in the classmap file. That is not even in the books.
You can generate the autoloader classmap with the classmap generator provided within Zend Framework 2. You can generate the autoload_classmap.php file so it is populated with all the php classes in your module.
Usage:
$ cd module/MyModule
$ ../../vendor/zendframework/zendframework/bin/classmap_generator.php -w
This works in the case you loaded Zend Framework 2 with composer, which loads the library in the vendor/ directory.
in Module.php after name add the two lines of code!
namespace Helloworld;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
Related
I performed the following steps and have an error
step 1
Insert en composer.json
"barryvdh/laravel-dompdf": "0.6.*"
step 2
install
php composer update
step 3
add config/app.php
'providers' => [....
Barryvdh\DomPDF\ServiceProvider::class,
'aliases' => [....
'PDF' => Barryvdh\DomPDF\Facade::class,
step 4
routes.php
Route::resource('pdf', 'PdfController');
step 5 create controller from php artisan make:controller PhpController
insert code:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
class PdfController extends Controller
{
public function Index() {
$pdf = App::make('dompdf.wrapper');
$pdf->loadHTML('<h1>Test</h1>');
return $pdf->stream();
}}
step 5 ERROR
call url localhost/public/pdf
FatalThrowableError in PdfController.php line 16:
Fatal error: Class 'App\Http\Controllers\App' not found
line 22 ....
$pdf = App::make('dompdf.wrapper');
Thank you! for your comments.
You'll have to use the App Facade
use Illuminate\Support\Facades\App;
Try to use this code
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App;
You forgot to prefix the App namespace with \. The correct way to call that function would be as follows:
$pdf = \App::make('dompdf.wrapper');
I want to use mPDF in a controller as follows (test scenario):
function indexAction() {
require_once('libraries/mpdf/mpdf.php');
var_dump(class_exists('mPDF')); //prints true
$mpdf = new mPDF(); //fails with 'class not found in Application/Controller (current namespace)
}
The class mPDF is declared inside the mpdf.php file and i've checked if the file gets loaded and it does.
To solve this you have to add \ infront of the class name to reset namespace
function indexAction() {
require_once('libraries/mpdf/mpdf.php');
var_dump(class_exists('mPDF')); //prints true
$mpdf = new \mPDF(); //fails with 'class not found in Application/Controller (current namespace)
}
error message is the clue to this
//fails with 'class not found in Application/Controller (current namespace)
I however dont know why the class_exist returns true. It did not do that when i had my class in autoload_classmap.php but when i require_once i got the same problem.
also if you dont want to require_once the php file in the function you can add it to class mapp file at the root of the module
<?php
// Generated by ZF2's ./bin/classmap_generator.php
return array(
'mPDF' => __DIR__ . 'path/to/file/mpdf.php',
);
I do this with PHPMailer
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial\public\index.php:
<?php
/**
* This makes our life easier when dealing with paths. Everything is relative
* to the application root now.
*/
chdir(dirname(__DIR__));
// Decline static file requests back to the PHP built-in webserver
if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) {
return false;
}
// Setup autoloading
require 'init_autoloader.php';
// Run the application!
Zend\Mvc\Application::init(require 'config/application.config.php')->run();
If I place a file in the same directory called console.php:
<?php
echo __DIR___
?>
and run:
php console.php
The output is:
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial\public
Clearly this seems to be the wrong directory as 'init_autoloader.php' is actually located here:
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial
Also my book says that the line:
Zend\Mvc\Application::init(require 'config/application.config.php')->run();
calls the bootstrap() method of the Zend\Mvc\Application. I'm not sure how a call to init() translates to a call to bootstrap() could someone please explain this to me?
My book also says that the call to init takes care of instantiating a new ServiceManager object although I'm not sure how because I see nothing in the bootstrap method of the Application model that has anything to do at all with ServiceManager. Could someone explain this to me?
Thank you for posting...
For reference zf2-tutorial/Module/Application/Module.php
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* #link http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository
* #copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
Clearly this seems to be the wrong directory as 'init_autoloader.php' is actually located here: C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial
The output from your console.php is different because in index.php you'll see this line ...
chdir(dirname(__DIR__));
This effectiveley changes up one directory to C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial which is the root of the application and the same folder in which init_autoloader.php is located.
Also my book says that the line: Zend\Mvc\Application::init(require 'config/application.config.php')->run(); calls the bootstrap() method of the Zend\Mvc\Application.
You are confusing the Zend\Mvc\Application with the skeleton application module named Application. They are not the same thing.
The bootstrapping being referred to by your book is happening here in the code ...
https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Application.php#L247-L261
As you can see it's a static method, which instantiates the ServiceManager and proceeds to set up services before finally bootstrapping the application here ...
https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Application.php#L136-L158
For further reading I'd suggest familiarizing yourself with the MVC layer by reading the docs here
http://framework.zend.com/manual/2.3/en/modules/zend.mvc.intro.html
I have an application with some modules. One of them is CourseSearch. Now I want to add a further one, the SportsPartnerSearch. Since these two modules are very similar to each other, I simply "cloned" / copied the CourseSearch and replaced all "Course" with "SportsPartner" (in all variations: $course to $sportsPartner, course-...phtml to sports-partner-...phtml etc.), in order to edit the logic in the second step. Now I'm getting following errors:
Warning:
require_once(/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php):
failed to open stream: No such file or directory in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Fatal error: require_once(): Failed opening required
'/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php'
(include_path='.:/usr/share/php:/usr/share/pear') in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Why is the path to the file being built in such strange way: /path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php? Where did I do a mistake?
Some additional information.
The class, that cannot be found because the wron path is CourseSearch\View\Helper\CourseSearchForm in the CourseSearch module. It can be found, when I deactivate the new module SportsPartnerSearch, that contains the class SportsPartnerSearch\View\Helper\SportsPartnerSearchForm.
The CourseSearchForm view helper is instanciated in the CourseSearchForm\Module
class Module {
public function getViewHelperConfig() {
return array(
'factories' => array(
'courseSearchForm' => function($serviceManager) {
$helper = new View\Helper\CourseSearchForm(array('render' => true, 'redirect' => false));
// ERROR. This code is not executed anymore.
$helper->setViewTemplate('course-search/course-search/course-search-form');
$courseSearchForm = $serviceManager->getServiceLocator()->get('CourseSearch\Form\CourseSearchForm');
$helper->setCourseSearchForm($courseSearchForm);
return $helper;
}
)
);
}
}
And called in the layout file:
echo $this->courseSearchForm();
The SportsPartnerSearch\View\Helper\SportsPartnerSearchForm is instanciated in the same way in the SportsPartnerSearch\Module#getViewHelperConfig() and is not called yet.
Have you generated a classmap? Check the autoload_classmap.php file in both the CourseSearch and the SportsPartnerSearch modules. I guess you still have an old classmap lying around. I think the problem is hidden inside the classmap because of the error in the ClassMapAutoloader from Zend, and not the standard autoloader.
You can generate a new classmap with the classmap generator provided in ZF2 (assuming you load it via Composer) with:
cd module/SportsPartnerSearch
../../vendor/bin/classmap_generator.php
This will generate a new classmap file inside the SportsPartnerSearch module.
How to load namespace for all modules (global autoload for whole application)
So far I need to add this to each module:
public function getAutoloaderConfig()
{
return array(
/* ... */
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
/* ... */
'MyNameSpace' => __DIR__ . '/../../library/MyNameSpace',
),
),
);
}
how can I implement this functionality in application.config.php? (i just want to load some base classes for whole application)
To load the modules you need use the file /config/application.config.php
Add the list of your modules to the array under module key.
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'Pages',
'ModuleName',
),
// ..... rest of array
)
The function getAutoloaderConfig() and getConfig() are used to load the configuration of the module (module internal configuration).
http://framework.zend.com/manual/2.0/en/user-guide/modules.html
autoload that path in your index.php, i.e.,
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../../library/MyNameSpace');
spl_autoload_register(function ($class) {
if(!class_exists($class)) {
$class = str_replace('\\', '/', $class) . '.php';
require_once($class);
}
});
I don't think that you can (or should) do this in the application.config.php file. The whole point behind modules in the ZF2 framework is to separate logic into reusable, independent bits of code. As such, each module maintains and manages its own configuration, including autoloading, independent of the main application or other modules. These settings can often be overridden with the .global.php and .local.php files of the main autoload/ directory, but the autoloading should be left to each individual module.
If the modules you're trying to include are custom pieces of code that you have developed, then perhaps you might want to look at whether they are actually modules at all, or simply code that belongs in the Application module.