Zend 2 Plugin Manager cant find class - plugins

Im new to Zend 2 and are trying to migrate my Zend 1 project to Zend 2. I had an Acl plugin in my Zend 1 project that I shared with several apps using symlink. I thought now that I migrate to Zend 2 I'd create my own package in the Vendor folder. I downloaded the Skeleton project and tried to add my plugin as this:
in the vendor folder I create myname\commons\Acl and added a my Module.php
in myname\commons\Acl i created src\WebAcl\Controller\Plugin and a added WebAclPlugin.php with the namespace WebAcl\Controller\Plugin
In my myname\commons\Acl I created ./config and added module.config.php with the content
return array(
// added for Acl ###################################
' controller_plugins' => array(
'invokables' => array(
'WebAclPlugin' => 'WebAcl\Controller\Plugin\WebAclPlugin',
)
),
// end: added for Acl ###################################
);
When I run this I get:
Fatal error: Class 'WebAcl\Controller\Plugin\WebAclPlugin' not found in AbstractPluginManager.php on line 170
What am I doing wrong?
Edit: If I in my module specify the classmap it works
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
)
But if I use "autoload" it doesnt work
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
Edit 2: This solved the problem:
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' *.str_replace("\\", "/", __NAMESPACE__),*
),
),
Still Im trying to figure out what composer.phar actually does? See additional question:
Additional question: I read that I should add my namespace in composer.json and run composer.phar update, which adds it to auto_namespace. I did this, but do I need to when I specify it in my module? Sorry if my questions are stupied.

The plugin manager will try to load the class using new which will make the registered autoloaders try to load the class. If there isn't an autoloader that can load this class, then you'll get the fatal error.
You don't say if myname\commons\Acl is a ZF2 module or a composer loaded package.
If it's a composer package, then you need to add:
"autoload": {
"psr-4": {
"WebAcl\\": "myname/commons/Acl/src/WebAcl"
}
}
to composer.json and then run composer.phar dumpautoload.
If you want myname/commons/Acl to be a module, then you need to add a Module.php to myname/commons/Acl that looks like this:
<?php
namespace WebAcl;
class Module
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
You now need to tell your application's ModuleManager to load this module in application.config.php:
Add 'WebAcl' to the list of 'modules'
Add the path to the module in the 'module_paths' key:
'module_paths' => array(
'WebAcl' => "./vendor/myname/commons/Acl",
'./module',
'./vendor',
),
You have to do this as there isn't a direct mapping from the namespace name (WebApi) to the path name on disk like there usually is in the ./modules directory.
The ModuleManager should now find your module and the autoloader should be able to autoload any file in the WebAcl namespace within vendor/myname/commons/Acl/src/WebApi.
Of course, the composer route is easier if you don't need any other features of a ZF2 Module.

Related

using Doctrine With laminas project issue : "Class does not exist"

I just installed Doctrine with my Laminas project. I added a database connection and generated my entities in the Application folder (Application\Entity). I added my entities settings to the module.config.php file in the Application folder. I created a new User and everything, including routing, is working fine. However, when I try to fetch all data from my table to view, the screen displays an error: 'Class 'Application\Entity\User' does not exist'.
i can't find any solution
module
|_Application
|_config
|_Entity
|_src
|_view
|_User
|_config
|_src
|_view
entities settings : namespace : Application
<in Application folder - module.config.php>
'doctrine' => [
'driver' => [
__NAMESPACE__ . '_driver' => [
'class' => AnnotationDriver::class,
'cache' => 'array',
'paths' => [__DIR__ . '/../Entity']
],
'orm_default' => [
'drivers' => [
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
],
],
],
],
````
**UserManager**
```
namespace : User\Manager
```
```
public function listUsers()
{
$query = $this->entityManager->getRepository(User::class)->findAll();
return $query;
}
```
**UserController**
```
namespace : User\Controller
```
```
public function listUserAction()
{
$data = $this->usermanager->listUsers();
var_dump($data);
die();
$view = new ViewModel([
'users' => $data
]);
return $view;
}
```
`Entity Folder => Path : Application\Entity`
As this question was already answered in the Laminas forums, I think I should complete this question here, too.
Your folder structure is wrong. The folder where your entities are stored must be a subfolder of the src folder of your application.
./module/Application/src/Entity/User.php
In Laminas projects all business logic is stored in the src folder. The Laminas autoloading will try to receive all classes from there.

Set Module name, Controller name, and Action name in Zend framework?

I recently started programming with Zend Framework.I want to change module name, controller name and action name of a module in my framework through coding, while coding in the same framework.
Its name is Application(module & controller) and I want to change it to Institute. Is this possible through coding?
I searched through Google for help, but either i couldn't find it or understand it properly. Any help would be appreciated.
This is really just a case of renaming things:
Update all namespaces from Application to Institute in all the classes in the module including the Module.php
Update the name of the controller and it's entry in config/module.config.php
Make sure you update the name of your view directory if you have one in the module, ie view/application/index etc to view/institute/index and make sure you update the entry in module.config.php to the same path
Update name of Application directory to Institute
Update the name in the array of modules in modules.config.php or if you are using an earlier version application.config.php from under the modules key.
That's all I can think of you would need to do
******** EDIT ********
So the basic idea would be as follows:
Add a console in a new module (I've used zend mvc console but you should probably use https://github.com/zfcampus/zf-console as mvc console is deprecated)
module.config.php
<?php
namespace Rename;
use Zend\ServiceManager\Factory\InvokableFactory;
return [
'console' => array(
'router' => array(
'routes' => array(
'rename-module' => array(
'options' => array(
'route' => 'module rename <moduleNameOld> <moduleNameNew>',
'defaults' => array(
'controller' => Controller\IndexController::class,
'action' => 'rename'
)
)
)
)
)
),
'controllers' => [
'factories' => [
Controller\IndexController::class => InvokableFactory::class,
],
],
];
IndexController.php
<?php
namespace Rename\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Console\Request as ConsoleRequest;
use Zend\Mvc\Console\Controller\AbstractConsoleController;
class IndexController extends AbstractConsoleController
{
public function renameAction()
{
$request = $this->getRequest();
// Make sure that we are running in a console and the user has not tricked our
// application into running this action from a public web server.
if (!$request instanceof ConsoleRequest) {
throw new \RuntimeException('You can only use this action from a console!');
}
$moduleNameOld = $request->getParam('moduleNameOld');
$moduleNameNew = $request->getParam('moduleNameNew');
$module = file_get_contents(getcwd() . "/module/$moduleNameOld/src/Module.php", 'r+');
$updatedModule = str_replace($moduleNameOld, $moduleNameNew, $module);
file_put_contents(getcwd() . "/module/$moduleNameOld/src/Module.php", $updatedModule);
rename("module/$moduleNameOld", "module/$moduleNameNew");
}
}
This can be run like
php public/index.php module rename Application Institute
I've only done renaming the module here and renaming the namespace in the Module.php
to finish this off you would need to recursively find all .php files in the Application directory and loop over applying the string replace (which should be improved really). Then you could update the view and application level config too with similar logic and using the steps above.
The code I've written is pretty bad and probably insecure but might help you along the way

Zend: Using forms in modules

I'm trying to use forms with modules, they should be stored inside the module. So at first my filestructure:
application/
(...other directories)
modules/
group/
controllers/
IndexController.php
(...controllers)
forms/
Create.php
views/
scripts/
(...view scripts)
Bootstrap.php
Within the IndexController, I'm trying to set the Form by
new Group_Form_Create()
and the class in Create.php is of course Group_Form_Create. I get the following error message:
Fatal error: Class 'Group_Form_Create' not found in (...)\application\modules\group\controllers\IndexController.php on line 380
The Bootstrap.php with the class Group_Bootstrap is just an empty class.
Actually, I'm using the default Zend structure, but it woun't work anyway. Any ideas wheres the problems or what could be a possible solution?
In my module bootstrap (APPLICATION_PATH/modules/group/Bootstrap.php), if use the following code:
//Loads the autoloader resources
$this->_moduleName = 'group';
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH ."/modules/".$this->_moduleName."/",
'namespace' => '',
'resourceTypes' => array(
//Tells the application where to find the forms
'form' => array(
'path' => 'forms/',
'namespace' => ucfirst($this->_moduleName).'_Form_'
),
//Tells the application where to find the models
'model' => array(
'path' => 'models/',
'namespace' => ucfirst($this->_moduleName).'_Model_'
)
)
));
I then call the forms or models like this:
$frm = new Group_Form_Create();
I use the same snippet in all my modules and I only change the value of the $this->_moduleName; each time.
Hope this helps !
It sounds like your module bootstraps are not being run. These are triggered by the module resource, which is loaded if you have:
resources.modules[] = ""
in your application.ini. So add this if it is not present.
Ideally, it should work out of box.
Add this in your bootstrap:
protected function _initAutoload() {
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'Group_',
'basePath' => dirname(__FILE__),
));
Zend_Loader_Autoloader::getInstance()->setFallbackAutoloader(true);
return $autoloader;
}

ZF-Autoloader not working in UnitTests on Ubuntu

i got a problem regarding Unit-testing a Zend-Framework application under Ubuntu 12.04. The project-structure is a default zend application whereas the models are defined as the following
./application
./models
./DbTable
./ProjectStatus.php (Application_Model_DbTable_ProjectStatus)
./Mappers
./ProjectStatus.php (Application_Model_Mapper_ProjectStatus)
./ProjectStatus.php (Application_Model_ProjectStatus)
The Problem here is with the Zend-specific autoloading. The naming convention here appears that the folder Mappers loads all classes with _Mapper but not _Mappers. This is some internal Zend behavior which is fine so far.
On my windows machine the phpunit runs without any Problems, trying to initiate all those classes.
On my Ubuntu machine however with jenkins running on it, phpunit fails to find the appropriate classes giving me the following error
Fatal error: Class 'Application_Model_Mapper_ProjectStatus' not found
in /var/lib/jenkins/jobs/PAM/workspace/tests/application/models/Mapper/ProjectStatusTest.php
on line 39
The error appears to really be that the Zend-Autoloader doesn't load from the ubuntu machine, but i can't figure out how or why this works. The question remains of why this is. I think i've double checked every point of contact with the zend autoloading stuff, but i just can't figure this out. I'll paste the - from my point of view relevant snippets - and hope someone of you has any insight to this.
Jenkins Snippet for PHPUnit
<target name="phpunit" description="Run unit tests with PHPUnit">
<exec executable="phpunit" failonerror="true">
<arg line="--configuration '${basedir}/tests/phpunit.xml' --coverage-clover '${basedir}/build/logs/clover.xml' --coverage-html '${basedir}/build/coverage/.' --log-junit '${basedir}/build/logs/junit.xml'" />
</exec>
</target>
./tests/phpunit.xml
<phpunit bootstrap="./bootstrap.php">
... this shouldn't be of relevance ...
</phpunit>
./tests/bootstrap.php
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
Any help will be appreciated.
I actually think the problem is with your "models/Mappers" folder. It should be "models/mappers" (all lowercase), and would explain why it works on Windows and not Linux.
As you can see from the Zend_Application_Module_Autoloader class:
$this->addResourceTypes(array(
'dbtable' => array(
'namespace' => 'Model_DbTable',
'path' => 'models/DbTable',
),
'mappers' => array(
'namespace' => 'Model_Mapper',
'path' => 'models/mappers',
),
However, as per my previous answer, I still believe you will need to bootstrap the application for all the default resources to be added automatically
From the ZF Manual:
Create a Model and Database Table
Before we get started, let's consider something: where will these classes live, and how will
we find them? The default project we created instantiates an
autoloader. We can attach other autoloaders to it so that it knows
where to find different classes. Typically, we want our various MVC
classes grouped under the same tree -- in this case, application/ --
and most often using a common prefix.
Zend_Controller_Front has a notion of "modules", which are individual
mini-applications. Modules mimic the directory structure that the zf
tool sets up under application/, and all classes inside them are
assumed to begin with a common prefix, the module name. application/
is itself a module -- the "default" or "application" module. As such,
we'll want to setup autoloading for resources within this directory.
Zend_Application_Module_Autoloader provides the functionality needed
to map the various resources under a module to the appropriate
directories, and provides a standard naming mechanism as well. An
instance of the class is created by default during initialization of
the bootstrap object; your application bootstrap will by default use
the module prefix "Application". As such, our models, forms, and table
classes will all begin with the class prefix "Application_".
Since Zend_Application_Module_Autoloader is loaded by default, you should only need to bootstrap your application (you don't have to run the front controller) as per the example at the of this answer.
If you don't want to bootstrap your application, you could short circuit the resource loading by initialising Zend_Application_Module_Autoloader yourself:
$autoloader = new Zend_Application_Module_Autoloader();
As you can see from the code, the __construct of this class calls initDefaultResourceTypes(), with all the goodies you are looking for:
class Zend_Application_Module_Autoloader extends Zend_Loader_Autoloader_Resource
{
/**
* Constructor
*
* #param array|Zend_Config $options
* #return void
*/
public function __construct($options)
{
parent::__construct($options);
$this->initDefaultResourceTypes();
}
/**
* Initialize default resource types for module resource classes
*
* #return void
*/
public function initDefaultResourceTypes()
{
$basePath = $this->getBasePath();
$this->addResourceTypes(array(
'dbtable' => array(
'namespace' => 'Model_DbTable',
'path' => 'models/DbTable',
),
'mappers' => array(
'namespace' => 'Model_Mapper',
'path' => 'models/mappers',
),
'form' => array(
'namespace' => 'Form',
'path' => 'forms',
),
'model' => array(
'namespace' => 'Model',
'path' => 'models',
),
'plugin' => array(
'namespace' => 'Plugin',
'path' => 'plugins',
),
'service' => array(
'namespace' => 'Service',
'path' => 'services',
),
'viewhelper' => array(
'namespace' => 'View_Helper',
'path' => 'views/helpers',
),
'viewfilter' => array(
'namespace' => 'View_Filter',
'path' => 'views/filters',
),
));
$this->setDefaultResourceType('model');
}
}
To only bootstrap your application without running the front controller in tests/bootstrap.php:
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
$config = array(
APPLICATION_PATH . '/configs/application.ini'
);
// Create application, bootstrap, and run
$application = new Zend_Application(
APPLICATION_ENV,
array('config' => $config)
);
$application->bootstrap();
Since the conventional Autoloader did not work, i tried to manually do what any Zend application would do. Here's the bootstrap.php that worked out in the end
<?php
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../application'));
// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'testing'));
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
require_once 'Zend/Loader/Autoloader.php';
require_once 'Zend/Loader/Autoloader/Resource.php';
$resources = new Zend_Loader_Autoloader_Resource(array(
'namespace' => 'Application',
'basePath' => APPLICATION_PATH
));
$resources->addResourceType('form','forms','Form');
$resources->addResourceType('model','models','Model');
$resources->addResourceType('dbtable','models/DbTable','Model_DbTable');
$resources->addResourceType('mapper','models/Mappers','Model_Mapper');
The logic usually is what Zend should figure out on his own. And in fact it does so on my local development machine running on windows. On ubuntu however i need to become specific.
Would be interesting to know why that is. If someone can explain the reasoning to me, then I'll probably end up giving you the right answer ;)

Zend Framework - Best Way To Autoload From /Application/Api Folder

I'm trying to autoload Classes from within a folder contained in the application itself.
E.G.
/Application
|->Models
|->Custom
|->Object.php
Is this the best way to do it (from bootstrap.php)?
public function _initAutoLoad()
{
$resourceLoader = new Zend_Loader_Autoloader_Resource(array(
'basePath' => APPLICATION_PATH,
'namespace' => '',
'resourceTypes' => array(
'custom' => array(
'path' => 'custom/',
'namespace' => 'Custom',
))
));
}
Meaning from within any controller, I can call:
$object = new Custom_Object();
If you're not intending to prefix the class names with the application namespace (default Application), I'd simply put this stuff in library, eg
library/
Custom/
Object.php -> class Custom_Object
then add your Custom namespace to the autoloader in configuration (application.ini)
autoloadernamespaces[] = "Custom_"
If your class represents some kind of service, you could use the built-in Service resource type which is automatically autoloaded
application/
services/
Object.php -> class Application_Service_Object
Looks like the solution I had is the best... I can find anyways...