I'm developing a small php framework for personal use. I am trying to autoload classes with UniversalClassLoader which is used in Symfony, but when I try to use some these classes I got error
Fatal error: Class 'Controller' not found in /opt/lampp/htdocs/web/globeapi/Start.php on line 14
Here is Start.php file code.
require('../libraries/loader/Loader.php');
use Symfony\Component\ClassLoader\UniversalClassLoader;
$auto = require('../config/Auto.php');
$Loader = new UniversalClassLoader();
$Loader->registerNamespaces($auto);
$Loader->register();
Controller::test();
Here is code of Controller class
namespace Libraries\Controller;
class Controller
{
function Controller()
{
}
public static function test()
{
echo 1;
}
}
here is code of Auto.php file which returns array of classes for autoloading.
return array(
'Libraries\Controller' => '../libraries/controller/Controller.php',
'Libraries\Module' => '../libraries/module/Module.php',
'Libraries\View' => '../libraries/view/View.php',
'Libraries\Sammy' => '../libraries/sammy/Sammy.php',
'Libraries\Routes' => '../config/Routes.php'
);
My answer is using the current version of Symfony (2.2) and the UniversalClassLoader. The general idea is to follow the PSR-0 standard so that you don't have to define a mapping entry for each file. Just by following simple naming and location conventions your classes will be found - neat, isn't it? :-) (note that both directory and file names are case sensitive).
The directory structure (the vendor directory is created by composer)
app.php
composer.json
src
App
Libraries
Controller
Controller.php
vendor
symfony
class-loader
Symfony
Component
ClassLoader
The composer.json
{
"require": {
"symfony/class-loader": "2.2.*"
}
}
The content of app.php:
require_once 'vendor/symfony/class-loader/Symfony/Component/ClassLoader/UniversalClassLoader.php';
use Symfony\Component\ClassLoader\UniversalClassLoader;
$loader = new UniversalClassLoader();
$loader->registerNamespace('App', 'src');
$loader->register();
\App\Libraries\Controller\Controller::test();
And finally the controller class:
//src/App/Libraries/Controller/Controller.php
namespace App\Libraries\Controller;
class Controller
{
public static function test()
{
echo 1;
}
}
Related
I have different versions of files which are stored in separate subfolders inside a main folder. I intend to use subfolder based on a dynamically determined value of $ver.
Can I create a psr-4 composer namespace for the main folder and then add to it the $ver for subfolders as needed.
I tried following but its showing errors.
File Structure:
web\
public\index.php
main\
V1\app.php
V2\app.php
V3\app.php
Composer:
"autoload": {
"psr-4": {
"Application\\": "main"
}
}
index.php:
use Application;
$ver = "V2"; // suppose its V2 for now
$app = new "\Application\" . $ver . "\App()";
app.php:
namespace Application;
class App {
}
You must follow PSR-4 for class naming and app structure:
composer.json
"autoload": {
"psr-4": {
"Application\\": "main"
}
}
main/V1/App.php
namespace Application\V1;
class App {}
For instance class with dynamic name use next construction:
$ver = "V2"; // suppose its V2 for now
$appClass = "\Application\$ver\App";
$app = new $appClass;
Read more about this here
And i recommend to use factory pattern for this case:
class App implements AppInterface {}
class AppFactory
{
public static function makeApp(string $version): AppInterface
{
$appClass = "\Application\$version\App";
if(! class_exists($appClass){
throw new Exception("App version $version not exists");
}
return new $appClass;
}
}
I want to use dependency injection to pass an instance of Plates to my controllers with PHP-DI that is integrated with my routing system Simple Router.
I've tried to inject an instance of Plates, but I get this error:
<?php
namespace Controllers;
use \League\Plates\Engine;
use \League\Plates\Template\Template;
use \League\Plates\Extension\Asset;
class Controller {
public function __construct(\League\Plates\Engine $templates)
{
$this->templates = $templates;
}
?>
Uncaught LogicException: The template name "home" is not valid. The default directory has not been defined
How I can solve this issue? I need also to pass the assets path with the asset() method. Any help will be appreciated.
UPDATE
Thanks to the help of jcHache I've managed the injection of a Plates instance inside my base controller with this DI code:
<?php
// config.php
return [
League\Plates\Engine::class => DI\create()
->constructor(TEMPLATE_ROOT)
->method('loadExtension', DI\get('League\Plates\Extension\Asset')),
League\Plates\Extension\Asset::class => DI\create()
->constructor(APP_ROOT),
];
index.php file
<?php
use Pecee\SimpleRouter\SimpleRouter;
use DI\ContainerBuilder;
$container = (new \DI\ContainerBuilder())
->useAutowiring(true)
->addDefinitions('config.php')
->build();
SimpleRouter::enableDependencyInjection($container);
This is great but I'm facing a problem and I can't find a fix for it.
I get this error that is relative to the assets loader of plates, it seems that it's instantiated more than once. I've extended my controllers with my base controller where the asset loader is instantiated, but I don't think is this the problem? Is there a fix?
Uncaught Pecee\SimpleRouter\Exceptions\NotFoundHttpException: The template function name "asset" is already registered
Plates engine factory require a view folder parameter (see Plates doc):
so you have to add this creation in your PHP-DI configuration file:
For Plates V4:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return League\Plates\Engine::create('/path/to/templates', 'phtml');
},
];
For Plates V3, I'll try:
// config.php
return [
// ...
\League\Plates\Engine::class => function(){
return new League\Plates\Engine('/path/to/templates');
},
];
or
// config.php
return [
// ...
\League\Plates\Engine::class => DI\create()
->constructor('/path/to/templates')
,
];
Design Note:
Personally, I won't use dependency injection for a template engine, I think it would be better to instantiate Plates engine in a base controller class.
namespace controllers;
use League\Plates\Engine;
abstract class BaseController
{
/**
* #var \League\Plates\Engine
*/
protected $templates;
public function __construct()
{
$this->templates=new Engine(\TEMPLATE_ROOT);
$this->templates->loadExtension(new \League\Plates\Extension\Asset(\APP_ROOT));
}
protected function renderView(string $viewname, array $variables=[])
{
return $this->templates->render($viewname,$variables);
}
}
For a child controller using Plates:
namespace controllers;
class MyController extends BaseController
{
public function index()
{
return $this->renderView('home');
}
}
I just figured out how to install and use PHP composer and used it to instal php-sql-query-builder to my project. The system created the vendor folder, etc. however I am having issues using classes within the package. It gives me the following error, any suggestions on how I can fix this?
Fatal error: Uncaught Error: Class 'NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder' not found in D:\Documents\CadetPortal\php\lib\login.class.php on line 15
Login.class.php
require_once ("core.class.php");
require_once ("../../vendor/autoload.php");
use NilPortugues\Sql\QueryBuilder\Builder\GenericBuilder;
class LoginSystem {
private $core;
private $builder;
private $config;
function __construct(){
$this->core = new coreFunctions();
$this->builder = new GenericBuilder();
$this->config = require('core.config.php');
}
//....
}
EDIT
fncregister.php
require_once "../../vendor/autoload.php";
$LoginManager = new \ThomasSmyth\LoginSystem();
echo $LoginManager->Register($_POST["StrSurname"], $_POST["StrForename"], $_POST["StrEmail"], $_POST["StrPassword"], $_POST["DteDoB"], $_POST["StrGender"], $_POST["StrToken"]);
composer.json
{
"require": {
"nilportugues/sql-query-builder": "^1.5"
},
"autoload": {
"psr-4": {
"ThomasSmyth\\": "php/lib/"
}
}
}
Your class source files shouldn't have any require_once statements at all in them. Follow the PSR-4 spec for naming. Put your classes in a namespace to avoid collision with other classes you might include via composer. Then put one class in one file, named the same as the class. For example, the LoginSystem class should be in a file named LoginSystem.php.
namespace MyNamespace;
class LoginSystem
{
...
}
Then set your composer.json to point your namespace to your source directory:
"autoload": {
"psr-4": {
"MyNamespace\\": "src/"
}
},
Now, your main app invoker or front controller should be the only place that includes the autoloader:
require_once 'vendor/autoload.php';
$login = new \MyNamespace\LoginSystem();
...
I am trying to include a third party library into my Symfony 2 project as explained here. However, I keep getting the error message Fatal error: Class 'Sprain_Images' not found in /src/MyProject/MyBundle/Controller/BackendController.php on line 267.
Here is what I did:
I put a third party class into the src folder (not directly in vendors because this class is not available to be loaded by deps).
#Directory structure
-src
-MyProject
-vendor
-sprain
-lib
-Images
-src
Images.php
Then I created the class to be used:
# /src/vendor/sprain/lib/Images/Images.php
require_once __DIR__.'/src/class.Images.php';
class Sprain_Images extends Images {
}
I also registered the prefix in autoload.php:
# /app/autoload.php
$loader->registerPrefixes(array(
'Twig_Extensions_' => __DIR__.'/../vendor/twig-extensions/lib',
'Twig_' => __DIR__.'/../vendor/twig/lib',
'Sprain_' => __DIR__.'/../src/vendor/sprain/lib',
));
And eventually I called the class in my controller:
# /src/MyProject/MyBundle/Controller/BackendController.php
$image = new \Sprain_Images();
However the class is not being found. Where did I make the mistake?
The class Sprain_Images should be in src/vendor/sprain/lib/Sprain/Images.php.
You can read more about the PSR-0 standard : https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md#underscores-in-namespaces-and-class-names
You just need to modify your composer.json file for the autoload value:
http://getcomposer.org/doc/04-schema.md#autoload
//composer.json in your symfony 2.1 project
"autoload": {
"psr-0": {
"": "src/",
"YourLibrary": "src/location/of/lib"
}
},
And then in your controller for example:
namespace Acme\UserBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use YourLibrary\FolderName\ClassName.php;
class DefaultController extends Controller {
/**
* #Route("/")
* #Template()
*/
public function indexAction()
{
$lib = new ClassName();
$lib->getName();
return array('name' => $name);
}
}
I'm just really starting with the Zend Framework, and currently I'm having a problem with the Zend_Loader_PluginLoader.
I managed to get a module specific plugin working easily enough using the following code:
class Api_Bootstrap extends Zend_Application_Module_Bootstrap
{
protected function _initPlugins()
{
$loader = new Zend_Loader_PluginLoader(array(
'Api_Plugin' => 'application/modules/api/plugins',
));
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new Api_Plugin_ErrorControllerSelectorPlugin());
}
}
Edit: The class file is located at application/modules/api/plugins/ErrorControllerSelectorPlugin.php
I then tried to adapt this to get a plugin loaded for the whole application using:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAppAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'App',
'basePath' => dirname(__FILE__),
));
return $autoloader;
}
protected function _initPlugins()
{
$loader = new Zend_Loader_PluginLoader(array(
'My_Plugin' => 'application/plugins',
));
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Plugin_ModuleConfigLoaderPlugin());
}
}
But I'm getting errors:
Fatal error: Class 'My_Plugin_ModuleConfigLoaderPlugin' not found in /var/www/localhost/application/Bootstrap.php on line 22
Edit: The class file is located at application/plugins/ModuleConfigLoaderPlugin.php
So - since the files are where I would expect them to be as far as the prefix/path pairs sent to Zend_Loader_PluginLoader() and the code in both cases are the same, what's the difference?
How do I get it to recognise my application-level plugins?
If you want the app-level plugin to reside within the namespace My_, you either need to put the My folder out in the library folder or declare the app-level namespace to be My_.
Assuming that you already have other stuff within your top-level app that uses the App_ namespace, then the easiest thing would be the former: move your My folder out into the library.
So, the plugin would reside in:
library/My/Plugins/ModuleConfigLoaderPlugin.php.
Then make sure that your configs/application.ini registers the My_ namespace:
autoloaderNamespaces[] = "My_"
Then the app-level Bootstrap could contain something like:
class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
protected function _initAppAutoload()
{
$autoloader = new Zend_Application_Module_Autoloader(array(
'namespace' => 'App',
'basePath' => dirname(__FILE__),
));
return $autoloader;
}
protected function _initPlugins()
{
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Plugin_ModuleConfigLoaderPlugin());
}
}
Alternatively, since your plugin does not sem to require any params, you could instantiate it via configs/application.ini using:
resources.frontcontroller.plugins[] = "My_Plugin_ModuleConfigLoaderPlugin"