I'm trying to use PHP ActiveRecord with Silex, but something strange is happening with models autoloading:
// index.php
<?php require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
ActiveRecord\Config::initialize(function ($cfg) {
$cfg->set_model_directory(__DIR__.'/../model');
// ...
});
$app->get('/', function () {
$page = App\Model\Page::all();
// return ...;
});
// ../model/Page.php
<?php namespace App\Model;
class Page extends \ActiveRecord\Model {
}
When I'm opening a page, it says that "Class App\Model\Page not found".
If I manually require '../model/Page.php' - it works.
If I remove namespace from ../model/Page.php and use it like usual class:
$page = Page::all();
it works again.
What's wrong with the namespaces?
In the code you supplied above your model directory is written in lower case characters and when you use the class you use App\Model\Page. Change your directory from model to Model. You shall also check if your custom classes are correctly loaded by the autoload.php script. If that is not the case you have to update the composer.json file. Here is a simple example:
{
"require": {
"silex/silex": "~1.0",
"silex/web-profiler": "~1.0",
"monolog/monolog": ">=1.0.0",
"symfony/monolog-bridge": "~2.3",
...
},
"autoload": {
"psr-0": {
"HERE_GOES_YOUR_CUSTOM_NAMESPACE": "DIRECTORY_OF_NAMESPACE"
}
}
}
Also do not forget to update the composer after edition of your project settings!
Related
I'm trying to switch from the pimple container that comes bundled with Slim, to PHP-DI and I'm having an issue with getting the autowiring to work. As I'm restricted to using PHP 5.6, I'm using Slim 3.9.0 and PHP-DI 5.2.0 along with php-di/slim-bridge 1.1.
My project structure follows along the lines of:
api
- src
| - Controller
| | - TestController.php
| - Service
| - Model
| - ...
- vendor
- composer.json
In api/composer.json I have the following, and ran composer dumpautoload:
{
"require": {
"slim/slim": "3.*",
"php-di/slim-bridge": "^1.1"
},
"autoload": {
"psr-4": {
"MyAPI\\": "src/"
}
}
}
My api/src/Controller/TestController.php file contains a single class:
<?php
namespace MyAPI\Controller;
class TestController
{
public function __construct()
{
}
public function test($request,$response)
{
return $response->write("Controller is working");
}
}
I initially tried to use a minimal setup to get the autowiring working, just using the default configuration. index.php
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '/../../api/vendor/autoload.php';
$app = new \DI\Bridge\Slim\App;
$app->get('/', TestController::class, ':test');
$app->run();
However, this returned the error:
Type: Invoker\Exception\NotCallableException
Message: 'TestController'is neither a callable nor a valid container entry
The only two ways I could get it to work, is to place the TestController class in index.php directly (which makes me think PHP-DI isn't playing well with the autoloader) or to use the following extension of \DI\Bridge\Slim\App. However, as I need to explicitly register the controller class, this kinda defeats the point of using autowiring (unless I'm missing the point):
use DI\ContainerBuilder;
use Psr\Container\ContainerInterface;
use function DI\factory;
class MyApp extends \DI\Bridge\Slim\App
{
public function __construct() {
$containerBuilder = new ContainerBuilder;
$this->configureContainer($containerBuilder);
$container = $containerBuilder->build();
parent::__construct($container);
}
protected function configureContainer(ContainerBuilder $builder)
{
$definitions = [
'TestController' => DI\factory(function (ContainerInterface $c) {
return new MyAPI\Controller\TestController();
})
];
$builder->addDefinitions($definitions);
}
}
$app = new MyApp();
$app->get('/', ['TestController', 'test']);
$app->run();
If you want to call the test method the syntax is :
$app->get('/', TestController::class .':test');
// or
$app->get('/', 'TestController:test');
rather than
$app->get('/', TestController::class ,':test');
cf https://www.slimframework.com/docs/v3/objects/router.html#container-resolution
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 am trying to create my first composer package for Codeigniter 4. However, I always get an error Class 'Myapp\Settings\Greet' not found. I'm totally lost.
I created a folder inside the ThirdParty folder named myapp-settings. Inside of that folder is another folder called src and composer.json.
Here's the content of that composer.json
{
"name": "myapp/settings",
"description": ".",
"license": "MIT",
"minimum-stability": "dev",
"autoload": {
"psr-4": {
"Myapp\\Settings\\": "src"
}
},
"require": {}
}
I created a test file inside the src folder named Greet.php
<?php namespace Myapp\Settings;
class Greet
{
public function hello()
{
return 'Hey, there!';
}
}
On codeigniter's App\Config\Autoload.php
public $psr4 = [
'Myapp\Settings' => APPPATH . 'ThirdParty/myapp-settings/src'
];
Then on codeigniter's default controller I called it.
<?php namespace App\Controllers;
use Myapp\Settings\Greet;
class Home extends BaseController
{
public function index()
{
$h = new Greet();
echo $h->hello();
}
//--------------------------------------------------------------------
}
Once I run it I got an error Class 'Myapp\Settings\Greet' not found. APPPATH\Controllers\Home.php at line 9. How can I fix this?
Instead of editing the codeigniter's app/Config/Autoload.php, revert it and add these lines to the project composer.json:
"repositories": [
{
"type": "path",
"url": "app/ThirdParty/myapp-settings"
}
],
// "require": {
Then run composer require myapp/settings
Since I have also stuck at this problem, a GitHub repository is created just for it. You might check and clone, watch the commits to understand the steps.
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 want to use Doctrine 1 inside a Zend Framework 2 project. And it has the old underscore/directory class naming style. If I am right that is compatible with the PSR0 autoloading. So I configured it as I thought would be correct. But it's not. :-(
I get the following error, when accessing my AlbumController via browser:
Fatal error: Class 'AlbumApi\Controller\Doctrine_Query' not found in /project/application_zf2/module/AlbumApi/src/AlbumApi/Controller/AlbumController.php on line [...]
Where is my misconception?
This is my project structure
/project
/application
/application_zf2
/module/AlbumApi/src/AlbumApi/Controller
/AlbumController.php
/composer.json
/init_autoloader.php
/library
/Doctrine
/Doctrine/MoreDirectories
/Doctrine.php
composer.json:
{
"require": {
"php": ">=5.3.3",
"zendframework/zendframework": ">=2.2.4",
"zendframework/zend-developer-tools": "dev-master"
},
"include-path": ["../library/Doctrine"],
"autoload": {
"psr-0": {
"Doctrine_": "../library/Doctrine"
}
}
}
AlbumController
<?php
namespace AlbumApi\Controller;
use AlbumApi\Controller\AbstractRestfulJsonController;
use Zend\View\Model\JsonModel;
class AlbumController extends AbstractRestfulJsonController
{
public function getList()
{ // Action used for GET requests without resource Id
$query = Doctrine_Query::create()
->from('User b')
->where('b.plz LIKE ?', $plz.'%');
$result = $query->fetchArray();
return new JsonModel($result);
}
}
Doctrine 1 doesn't use namespaces, so you have to write \Doctrine_Query instead of just Doctrine_Query.