I'm writing a PHP application with Zend Framework 2.3.1.
I wrote a ZF2 module that I placed in vendor directory. vendor/TuxDrink.
That module requires another module that I placed in vendor/ServiceLocatorFactory (https://github.com/fezfez/ServiceLocatorFactory).
now.. I want to use the ServiceLocatorFactory Module inside my module. but that ServiceLocatorFactory directory is in the vendor directory of the application, not of my specific module.
my TuxDrink Module.php
<?php
namespace TuxDrink;
use Zend\ModuleManager\Feature\AutoloaderProviderInterface;
class Module implements AutoloaderProviderInterface
{
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
what exactly do I need to add in order for my TuxDrink module to detect the ServerLocatorFactory module and allow me to use it's classes.
for now I get
Fatal error: Class 'ServiceLocatorFactory' not found
any information regarding the issue would be greatly appreciated.
A couple of things/best-practices to consider:
1) If it's vendor/, it gets put there by composer. That way, all the autoloading is configured properly. Also, .gitignore typically ignores everything in vendor/, so keep that in mind.
2) That 'ServiceLocatorFactory' module is a very bad idea. The best practice is properly inject real dependencies - . A module whose purpose is to expose the ServiceManager globally is an anti-pattern. You'll never know what dependencies your classes have, because any of them can pull any dependency from anywhere.
It doesn't matter where the class is located as long is it can be autoloaded. Since the modules are in vendor/ I'm assuming you installed them using Composer (if not, you should).
Other than that, remember that the class is named ServiceLocatorFactory\ServiceLocatorFactory, not ServiceLocatorFactory which is what is shown in your error. (This may be the only issue.)
I'm also curious why you feel the need to have a module that makes the service manager a global
Related
I am not sure whether title of question is exactly what I want to ask.
I want to use Authorize.net in my Yii application. Authorize.net has an API consisting of multiple classes and in order for the API to work all the classes should be autoloaded. In its SDK there is one file named autoload.php that does that. Please note that autoload.php is NOT a class, it just contains a function. Here is its code:
spl_autoload_register(function($className) {
static $classMap;
if (!isset($classMap)) {
$classMap = require __DIR__ . DIRECTORY_SEPARATOR . 'classmap.php';
}
if (isset($classMap[$className])) {
include $classMap[$className];
}
});
By requiring this file in my code I can do work with API successfully. Like:
require 'sdk-php-master/autoload.php
//I can make successful API calls after requiring autoload.php to be loaded.
But now the problem is I want to make same API work in Yii. I placed the SDK folder in extensions directory. Now I need to set extension path to be able to use it in my application. Now the problem is what should I set in class name for in config.php to make it work?
I tried this:
'authorize' => array(
'class' => 'application.extensions.authorize.autoload',
),
But that does not work, and it should not since autoload.php is not a class. All the necessary classes that should be autoloaded are placed in application.extensions.authorize.lib directory. How should I autoload all of them in Yii since according to my knowledge we can only have one entry in config.php for class.
Here is the link to SDK and its directory structure. Authorize.net SDK
This library uses composer, i recommend to you to use composer in your project to manage your libraries, and you will have no hassle with autloads.
Basicly create composer.json in your root project directory and place authorize part in it (and any further things)
{
"require": {
"authorizenet/authorizenet": "~1.8"
}
}
In your main index.php place:
require '/path/to/vendor/autoload.php';
somewhere before require $yii
Then call composer install. This in in short, for more details about composer this guide should be fine.
Update:
Composer will greatly improve your workflow when your require some external libraries. However if you really don't wan't to use composer, then just require autoload.php in index.php
Then use this library classes as in docs. Do not configure it as extension - this library is not Yii specific. In any code part just use it, for example:
define("AUTHORIZENET_API_LOGIN_ID", "YOURLOGIN");
define("AUTHORIZENET_TRANSACTION_KEY", "YOURKEY");
$subscription = new AuthorizeNet_Subscription;
$subscription->name = "PHP Monthly Magazine";
...
I found the solution to this. I just imported all the required folders in config main.php like this:
'import' => array(
'application.extensions.*',
'application.models.*',
'application.components.*',
'application.extensions.authorize.*',
'application.extensions.authorize.lib.*',
'application.extensions.authorize.lib.shared.*',
),
You can autoload all Authorize.net files using the following code on your protected/config/main.php file:
Yii::setPathOfAlias('Authorize', dirname(__FILE__).'/../extensions/sdk-php-master');
Yii::import('Authorize.autoload', true);
This is because I want to develop a web platform with more than one application in the same project.
In any MVC web application we should have this default URL schema:
domain/controller/action/parameters
1: In Zend, what can I do (in which files) to change this schema to add the application name before the controller name?
Expected Result: domain/application/controller/action/parameters
2: How can I implement the consequences of this new URL block in terms that I will separate the MVC for each application, maintaining the shared resources in a separate directory? What changes may I do in Zend autoloader
Expected Result:
/public_html/
/public_html/platform
/public_html/platform/apps
/public_html/platform/apps/base (user interface container)
/public_html/platform/apps/crm
/public_html/platform/apps/crm/model
/public_html/platform/apps/crm/view
/public_html/platform/apps/crm/control
/public_html/platform/apps/crm/public
/public_html/platform/apps/crm/public/css (and etc.)
/public_html/platform/apps/erp
/public_html/platform/apps/erp/model
/public_html/platform/apps/erp/view
/public_html/platform/apps/erp/control
/public_html/platform/apps/erp/public
/public_html/platform/apps/erp/public/js (and etc.)
/public_html/platform/sys
/public_html/platform/sys/core
/public_html/platform/sys/cfg
/public_html/platform/libs/
/public_html/platform/libs/zend
/public_html/platform/libs/template_it
/public_html/platform/libs/custom
i think it is as easy as having actual different ZF2 application, every one in its own folder, and in the same level, a "vendor" folder where you put all the shared structure (coming from zend, third party libraries, etc).
Then inside the vendor folder, i would create another folder for your own shared code, including all your modules that has to be used by more than one of the applications, so your code is a library for yourself.
Since your app is actually in domain/application, and everyone has it own config, it is very straightforward to have domain/application/controller/action/parameters routes: you just create your normal controller/action/parameters routes, since the app actually resides in domain/application/ and the router doesnt have to care about it.
As you noticed, another problem is the autoloader. YOu just need to update the references to the shared modules inside your application.config.php for everyone of your apps
return array(
'modules' => array( //....
),
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php'
),
'config_cache_enabled' => false,
'cache_dir' => 'data/cache',
'module_paths' => array(
'./module',
'../vendor',//reference to your library modules
),
),
//...
);
of course, if the modules doesnt reside directly inside vendor/module but something like vendor/libraryname/module, you have to take a look at your autoload system (Composer autoloading or whatever) and add the classes or namespaces to the corresponding maps.
I've been looking for information on this question but the only answer I can find is by looking at how other modules take care of this. So far, I have seen this:
With CdliTwoStageSignup in Module.php
'factories' => array(
.
.
'cdlitwostagesignup_module_options' => function($sm) {
$config = $sm->get('Configuration');
return new Options\ModuleOptions($config['cdli-twostagesignup']);
},
.
}
With ZfcUser in Module.php
'factories' => array(
'zfcuser_module_options' => function ($sm) {
$config = $sm->get('Config');
return new Options\ModuleOptions(isset($config['zfcuser']) ? $config['zfcuser'] : array());
},
Based on Zend 2 documentation, ModuleManager Merges all the module.config.php of each module and is set in the service manager. Also, config files in .config/autoload directory can override the module config files.
To access the configurations, these two modules seem to use the keywords: "Config" and "Configuration".
Are these always the the keywords used with the service manager to get to config files?
Is there any difference between choosing one over the other?
Appreciate any answer you can provide.
The keywork used should be config. Internally, afaik, all key, aliases, etc.. will be turned from CamelCase to dash-separated-lowercase. So Config equals config as far as configuration is concerned.
Now when it comes down to configuration vs. config i assume configuration was left available as an alias to config. At one point, i think beta 4 or beta 5 they've decided that all occurences of configuration will be replaced by the well known abbreviated form of config. If ever there is any occurence of configuration that not acts as a fallback to config all community will appreciate you opening an issue on github to get it fixed.
I am building my first ZF2 application, and in one of my modules, the views associated with my controller are not loading. Is there a way I can check what view path ZF is trying to execute?
I have checked all of the file paths and module config settings, and they seem correct, and all of my other modules that have the same layout work fine, so I am thinking this is either a filename or namespace issue.
If you use Zend-developer-tools it shows you in the toolbar which layout, template is used.
To your problem - in module you can replace the template from other modules. But it should depend on template path stack.
In module.config.php, you should have something like:
'view_manager' => array(
'template_path_stack' => array(
'application' => __DIR__ . '/../view',
),
I developing a project using Zend framework and I came across the following problem. I'm using Zend framework MVC folder structure generated using their zf.sh script.
My library folder has the Zend library folder and it's classes can be called normally inside the application. I created another folder inside my library for my classes. This is the folder structure now:
MyProject
|_application
|_docs
|_public
|_library
|_Zend
|_Buyers
|_Donations.php
|_scripts
I named my Donation class "Buyers_Donations" as the Zend framework naming convention.
When I tried using this class inside my controller
$obj= new Buyers_Donation();
it gave an error can not find class Buyers_Donation inside the controller.
But when I added the following line in my Bootstrap it worked:
$loader = Zend_Loader_Autoloader::getInstance();
$loader->setFallbackAutoloader(true);
$moduleLoder = new Zend_Application_Module_Autoloader(
array(
'namespace'=>'',
'basePath'=>dirname(__FILE__)
));
Could someone please explain what actually happened and what is the use of the module autoloader although I don't have any modules in my application ?
As you suspected, you shouldn't be using the module autoloader since you're not using modules. Assuming the Zend* classes are autoloading correctly for you, all you need to do is tell the standard autoloader that it should also be used for classes in your 'Buyers' namespace. So instead of the code snippet you posted, just do:
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace('Buyers_');
you can also set this in application.ini if you prefer.
I'm also assuming that your classes are in the library folder, and not in the public directory as your question implies (this would be bad).
If you do not wish to use the zend's auto loading feature, you will have to include files manually by using require_once(), such as:
require_once 'Buyer/Donations.php';
If you do wish to use zend loader with your own library code that uses your own namespace, you may register it with the autoloader using the registerNamespace() method. in the bootstrap, you could do so as follows:
protected function _initAutoload()
{
$autoloader = Zend_Loader_Autoloader::getInstance()->
registerNamespace('Buyers_')
return $autoloader;
}
If the auto loader doesn't work, make sure you set the include path to the library folder somewhere. It's automatically added by the zend framework to public/index.php:
// Ensure library/ is on include_path
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));