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);
}
}
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'm building a PHP web application with Laravel and am trying to pass a name and email from a form to my database, but it displays this error:
Fatal error: Uncaught Error: Class 'user' not found in
C:\xampp\htdocs\MVC\app\controller\home.php:20 Stack trace: #0
C:\xampp\htdocs\MVC\app\core\app.php(43): home->create('hala',
'hala#yahoo') #1 C:\xampp\htdocs\MVC\public\index.php(4):
app->__construct() #2 {main} thrown in
C:\xampp\htdocs\MVC\app\controller\home.php on line 20
This is the code I'm using for the home page:
class home extends controller
{
public function index($name = '')
{
$this->view('home/index', ['name'=>$user->name]);
}
public function create($username = '', $email = '')
{
user::create([
'username' => $username,
'email'=> $email
]);
}
}
and the model:
use Illuminate\Database\Eloquent\Model as Eloquent;
class user extends Eloquent
{
public $name;
protected $fillable = ['username','email'];
}
What am I doing wrong and how can I fix it?
In your controller code, you need to include the user class:
require_once("user.class.php"); /* or whatever the file is named */
If this is done automatically and the class is in a different namespace, you need to declare your intent to use it in the controller:
use \my\namespace\user;
Or just use the fully qualified class name in your code:
\my\namespace\user::create();
If you use illuminate/database then chances are you are using composer. Why not add a PSR-4 auto load rule and structure your code accordingly. Eg. composer.json might look like this:
{
"name": "acme/acme",
"description": "Acme is this and that",
"type": "project",
"require": {
"php": "^7.2",
"illuminate/database": "^5.7"
},
"autoload": {
"psr-4": {
"Acme\\": "src"
}
},
"license": "proprietary"
}
Runing composer install makes you an vendor/autoloader.php and it is the only file you need to require. You put your own code un the Acme (or whatever you chose) namespace. Eg. You put your user model under src/Model/User.php and add your namespace:
<?php
namespace Acme\Model;
use Illuminate\Database\Eloquent\Model as Eloquent;
class User extends Eloquent
{
public $name;
protected $fillable = ['username','email'];
}
Your main file might look like this..
<?php
// entry point file
require_once('vendor/autoload.php');
use Acme\Model\User;
$user = new User();
// ...
Obviously you would make most logic in some class so this should be quite short.
This might seem obvious to people working on recent projects, but I have seen too many projects that still have a static file including all the classes like we did in the olden days. Move your projects to the 2010s now!
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'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;
}
}