H, my composer json file autoload with psr-4 a Class, but when a Call that Class, php return error: Error: Class 'ClassA\Tae' not found
Here json autoload
"autoload": {
"psr-4": {
"ClassA\\": "includes/ClassA/",
"": "includes/"
}
}
and my php class that require ClassA is this
require_once __DIR__ .'/../vendor/autoload.php';
use ClassA\{ Rate, Tae, Taeg };
class TestTaeg extends \PHPUnit\Framework\TestCase {
public function test_tae() {
$obj = Tae::init( 5, 12 );
}
Do you know why I cannot find ClassA ?
I run the code with phpunit on cli, with this syntax (is the first time that I use phpunit)
../vendor/phpunit/phpunit/phpunit ./test-general.php
Thx
Are you namespacing your classes right ? To be honest your psr-4 autoloading looks a bit messy, I am asuming you are autoloading everything even when you dont need those.
So if you please share a screenshot of your folder structure, I can try to recreate your issue and probably suggest a solution.
Related
I'm new to CI and am struggling to get my head around it.
I'm familiar with Laravel and Symfony and I'm finding it very difficult to test CI code.
I'm considering the service locator pattern to try and work around the dependency injection limitations, but right now I'm struggling with autoloading.
Let's say that I have a model like this:
<?php
class FooModel extends CI_Model
{
public function __construct()
{
parent::__construct();
$this->load->library('alertnotificationservice');
}
}
I want to write a test that looks like this:
<?php
namespace Test\AlertNotification;
// extends TestCase and offers reflection helper methods
use Test\TestBase;
class FooModelTest extends TestBase
{
public function test_my_method()
{
$objectUnderTest = new \FooModel();
}
}
When I run my test I get the error Error: Class 'CI_Model' not found.
I'm using CodeIgnitor 3.1.2 and it doesn't use composer or include the phpunit.xml.dist file that the version 4 manual refers to.
What is the "proper" way to get the autoloading to happen so that I can run my tests?
I haven't found a satisfactory way to do this. I ended up creating a bootstrap.php file that I include from phpunit.xml.dist
It looks something like this:
<?php
require(__DIR__ . '/../vendor/autoload.php');
// this is a copy of the default index.php shipped with CodeIgnitor
// The system and application_folder variables are replaced
// Also, in this version we do not bootstrap the framework and rather include our own version below
require('loader.php');
// this is a modified version of system/core/CodeIgniter.php
// they do bootstrapping, routing, and dispatching in one place
// so we can't use the whole file because dispatching fails when running tests
require('framework.php');
// set up the test environment database connection
putenv('DATABASE_HOST=localhost');
putenv('DATABASE_USER=user');
putenv('DATABASE_PASSWORD=password');
putenv('DATABASE=control_panel');
// CI uses a singleton approach and creates an instance of a child of this class during dispatch
// We need to make sure that the singleton holder is populated
$controller = new CI_Controller();
The framework.php is a stripped down version of that CodeIgnitor file where I've removed the routing and dispatch logic. I've put the files up as a Gist
The crux of the loading in CI seems to exist in system/core/Controller.php and the controller is intended to be something that lets "so that CI can run as one big super object". The load_class function (declared in system/core/Common.php) is responsible for hunting down and loading the class files.
I should also include my composer.json file. I'm using this for testing (CI 3.1.12 does not use composer)
{
"require": {
"guzzlehttp/guzzle": "^6.5"
},
"require-dev": {
"phpunit/phpunit": "^9.1"
},
"autoload": {
"psr-4": {
"Test\\": "tests/"
},
"classmap": ["application/", "system/"]
}
}
I would really like to avoid loading absolutely everything, and would like to be able to mock out bits and pieces, but I'm not optimistic that CodeIgnitor lends itself to this.
Anyway, this approach at least lets me boot my app. There has to be a better way of doing this, I can't believe that the framework could be so popular if it's so hard to test properly.
So subject is the question. Yes, I've searched this forum and googled too. All I've got - useless Symfony docs and casts, some general advises, cli-s and nothing case specific. Maybe yahoo or duckduck could help better?
Everyone is talking about bundles, about how it is important to create them, probably because under the hood Symfony is pushing users away from custom libraries, but no one is actually explains how to start using a bundle - how to start calling its methods.
No, my library is not a composer or whatever package. No, library methods do not return Response objects. No, I am not dealing with composer or recompilations or cli (I use Composercat). No, I will not put library to github or packagist to load it via composer or whatever because it is private library.
Sorry about emotional off-topic.
About the case: I've put my library into the folder
src/lib/MyLibrary.php
I suspect that library class is autoloaded, because if I do not extend Controller with it (if I declare class MyLibrary instead of class MyLibrary extends Controller) - Symfony spits "class name in use" error.
So question: in my controller how to call library method?
$this->get('MyLibrary') doesn't work.
echo print_r($this) doesn't show MyLibrary in this registry too.
Looks like library file is loaded but not registered and/or instantiated. If it is so, then where to point Symfony to register it?
So most of this question is really about how php manages classes. Not so much about Symfony. But that's okay.
To start with it would be best to move project/src/lib to just project/lib. Symfony has some scanning stuff going on in the src directory and you really don't want to have your library mixed up in it.
So:
# lib/MyLibrary.php
namespace Roman;
class MyLibrary
{
public function hello()
{
return 'hello';
}
}
Notice that I added a namespace (Roman) just to distinguish your code from Symfony's.
Now you need to tweak composer.json in order to allow php to autoload your classes:
"autoload": {
"psr-4": {
"App\\": "src/",
"Roman\\": "lib/"
}
},
After adding the Roman line, run "composer dump-autoload" to regenerate the autoload files.
After that, it's just a question of using regular php inside of your application:
# src/Controller/DefaultController.php
namespace App\Controller;
use Roman\MyLibrary;
use Symfony\Component\HttpFoundation\Response;
class DefaultController
{
public function index()
{
$myLibrary = new MyLibrary();
$hello = $myLibrary->hello();
return new Response($hello);
}
}
And that should get your started.
Whenever I try to extend a class I end up with
Fatal error: Class 'home\register\Create' not found in C:\xampp\htdocs\project\home\register\register.php on line 8
I have 2 file classes under the same directory first one an abstract class Create :
<?php
namespace home\register;
use home\libs\Tools\Sanitize\Sanitize as sanitize;
abstract class Create
{
public $sanitize;
function __construct ()
{
$this->sanitize = new sanitize();
if (isset($_POST)){
foreach ($_POST as $key => $value){
if (!empty($_POST["$key"])){
$this->$key = $this->sanitize->clean($value);
}
}
}
}
abstract function db_query($pdo_db_name, $password, $query, $host = 'localhost');
}
And a second class register which extends Create:
<?php
namespace home\register;
use PDO as pdo;
use home\libs\MainLogger\MainLogger as logger;
class register extends Create //Line 8 Error is thrown when extending the class
I can post the whole code but I doubt the problem is there. I've been trying to adapt to the structural design pattern as I see it as the tidiest way of handling a lot of classes
Right now
You'll need to ensure that Create is loaded before you can extend it in register.php. The simplest way to do this is using require_once, by adding something like:
require_once(__DIR__ . '/Create.php');
to the top of register.php. This should be sufficient for now.
Maybe later
Once you start to get into loading many classes, you may want to look at using an autoloader. From my experience the most flexible way to do this is to convert the project to using composer, and then using the autoload configuration item.
The layout of your classes (not including ones not shown in this question) would be something like:
src/register/Create.php
src/register/register.php
and, to match this, your composer.json would look something like:
{
"autoload": {
"psr-4": {"home\\": "src/"}
}
}
You can then generate the autoloader by running:
composer dump-autoload
and use it in the entry point to your project by adding:
require_once('vendor/autoload.php');
From this point on, you would not need to add individual require_once lines for each file, provided you re-ran dump-autoload after adding new classes to your source.
I have a problem with Codeception/AspectMock.
When using custom autoloader and try to create an instance of a class which has parent form the same custom namespace I have this error:
PHP Fatal error: Uncaught InvalidArgumentException: Class [parent
class name] was not found by locator in
vendor/goaop/parser-reflection/src/ReflectionEngine.php:112
I have very simple setup:
<?php
require_once __DIR__ . '/vendor/autoload.php';
$kernel = AspectMock\Kernel::getInstance();
$kernel->init([
'debug' => true,
'includePaths' => [__DIR__. '/lib'],
]);
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader
$b = new \lib\B();
Class \lib\B:
namespace lib;
class B extends A {}
Class \lib\A:
namespace lib;
class A
{
public function getName()
{
return static::class;
}
}
Class B is loaded via my custom autoloader, but then the locator tries to load parent class A via composer autoloader and returns this error. Is this a bug, or I'm doing something wrong?
The topic starter has already got an answer on GitHub.
In order to use custom autoloader you should re-init ReflectionEngine with composite class locator that will be able to locate your classes or you can use CallableLocator with closure for resolving paths.
Or, even better you could switch your code base to the PSR0/PSR-4
For example:
$kernel->loadFile(__DIR__ . '/autoload.php'); // custom autoloader
\Go\ParserReflection\ReflectionEngine::init(
new class implements \Go\ParserReflection\LocatorInterface {
public function locateClass($className) {
return (new ReflectionClass($className))->getFileName();
}
}
);
$b = new \lib\B(); // here you go
If you can easily do a find and replace on your codebase, maybe you could refactor your code to PSR-4 autoloading standards and do away with the need for a custom autoloader altogether.
This is the spec https://www.php-fig.org/psr/psr-4/. I'll try and explain it as simply as possible.
Imagine changing your lowercase namespace lib to Lib, and setting that namespace to the src/ directory in your composer.json:
"autoload": {
"psr-4": {
"Lib\\": "src/"
}
}
After setting that, run composer dumpautoload. Then all you need to do is search and replace namespace lib;, replacing with namespace Lib;.
An example class located in src/Form.php would have namespace Lib; at the top, followed by class Form.
<?php
namepace Lib;
class Form
{
// code
}
Namespaces use the folder naming convention. All classes directly in src/ have namespace Lib;. If there are subdirectories, the directory name becomes part of the namespace. For example a file in src/Form/Field/Text.php would have namespace Lib\Form\Field; class Text {}.
<?php
namepace Lib\Form\Field;
class Text
{
// code
}
You can see the full convention in the link above, but the general rule is make any folders begin with a capital letter, as with your classname, and the autoloader should be able to find all of your classes.
This is probably the best practice solution for you, and again as I said, only requires a little bit of file renaming and namespace tweaking. Good luck!
I'm running PHPUnit using a bootstrap file for autoloading classes (generated by composer).
All my tests load up classes just fine, but for two of my tests, I made a "base" test class which extends \PHPUnit\Framework\TestCase (similar to PHPUnit_Framework_TestCase before PHPUnit7), and then two test classes that extend the base class, similar structure to the following example code:
abstract class BaseTest extends \PHPUnit\Framework\TestCase
{
abstract function setUp();
protected function getCommonTestVariables()
{
// ...
}
protected function runCommonTests()
{
// ...
}
}
class BlahBlahTest extends BaseTest
{
public function setUp()
{
$variables=$this->getCommonTestVariables();
//etc...
}
public function testThings()
{
$this->runCommonTests();
}
}
Whenever I run this, PHPUnit gives an error:
Fatal error: Class 'BaseTest' not found in BlahBlahTest.php on line 13
I've checked filenames, locations, namespaces and everything seems to be in order. Any help would be appreciated to get to the bottom of this
I ran into the same problem and if you are not too familiar with the inner workings of both PHPUnit and Composer this can indeed seem perplexing.
PHPunit does not use use the Composer autoloader to find any of your test classes. It just scans any directory you give it and operates on one file at a time.
Hence it does not know about any other class than the one in the file it is currently operating on. That is where the bootstrap file comes into play.
If you want to use the Composer Autoloader to load other test classes, you need to tell it where it can find these test classes (and, optionally, in which namespace).
There are two ways to do this:
Add an autoload-dev section to your composer.json or
Add the test directory to the Composer Autoloader
Use autoload-dev
The autoload-dev sections allows you to define autoload rules for development purposes.
Quoting directly from the manual:
Classes needed to run the test suite should not be included in the
main autoload rules to avoid polluting the autoloader in production
and when other people use your package as a dependency.
Therefore, it is a good idea to rely on a dedicated path for your unit
tests and to add it within the autoload-dev section.
Example:
{
"autoload": {
"psr-4": { "MyLibrary\\": "src/" }
},
"autoload-dev": {
"psr-4": { "MyLibrary\\Tests\\": "tests/" }
}
}
Add to the Composer Autoloader
An alternative would be to get the Composer Autoloader and add your testing namespace (if you have any) and the directory where your tests live. How to do this, as described in the manual (at the bottom of the autoloading section in "Basic Usage") is :
$loader = require('/path/to/vendor/autoload.php');
$loader->add('Test\\', __DIR__ . '/Tests');
If your tests use namespaces that mirror the test directory and you still run into trouble, you can try omitting the prefix by replacing the first parameter ('Test\\') with ''.
If you want further insight into how all of this works you should take a look at the Composer ClassLoader class, especially the add() and findFile() methods.
For me the solution was much simpler.
I changed the capital letter of Test to test at the end of the file and the class name
BaseSomethingtest.php
<?php
namespace Something\Tests\Sub1\Sub2;
class BaseSomethingtest
{
}
I just put a word at the end of my base class. As far as it
didn't finish with Test, phpunit didn't call it
BaseSomethingTestCase.php
<?php
namespace Something\Tests\Sub1\Sub2;
class BaseSomethingTestCase
{
}
I'm not sure if you still need a solution, but this worked for me:
Non-testable base class extending PHPUnit_Framework_TestCase
In PHP 7.0+ extends PHPUnit_Framework_TestCasechanged to extends \PHPUnit\Framework\TestCase, try this one.