I'm using Codeception to TDD the development of a simple application in PHP. I've created my first unit test called DogTest.php with a simple assertion, but it's complaining about not being able to find the Dog class.
I have created a Dog.php file in the root directory, and also placed it under /src, but neither is working. I think this is either a namespace issue or an autoloader issue, but the Codeception documents (and the various TDD guides I've looked at) have this important detail missing.
Can someone please advise on how to get my DogTest to detect the Dog class?
In your composer.json, make sure you have added autoloading configuration. As an example:
"autoload":{
"psr-4":{
"Del\\":"src/"
}
}
Every file in src should have namespace Del. For instance, src/Blank.php would look like:
<?php
namespace Del;
class Blank
{
}
Whereas src/Http/Client.php would have namespace Del\Http.
Once added, run composer dumpautoload to generate the class maps. Your classes should now autoload without problems.
See my Blank starter project with codeception test for more info.
https://github.com/delboy1978uk/blank
Related
I am having difficulty getting psysh to instantiate classes.
I am trying to use PSR-4 namespaces, and have registered a psr-4 autoload in composer like this:
"autoload": {
"psr-4": {
"System\\": "phpclasses/"
}
},
There is a class in phpclasses\Test.php, class name Test with a static method called hello().
I open a command shell, start psysh, and psysh appears to be working normally.
If I try to run Test::hello(); it will fail, unless I call it like this first: echo System\Test::hello();
This actually fails with the message:
PHP Fatal error: Class 'System\Test' not found in eval()'d code on line 1
but then I can successfully run: echo Test::hello();
echo System\Test::hello(); will never work
I tried Use System; and use System\Test; has no beneficial effect.
Every class I use, I have to go through this routine, which is kind of a drag because some of the classes uses static methods, and each of those will only work if each class has gone through that fail first routine.
Basically the same technique must be used for static or non-static methods.
I am running psysh in a command shell in windows 10, xampp (php 5.6), composer (current) installed.
Any suggestions for what I am doing wrong or need to do differently?
The trouble here is that you're not following PSR-4. With the config you provided, it's expecting to find classes in the System namespace inside your phpclasses folder. So, for example, the file Test.php would have the class System\Test.
To just fix it, either change the prefix in your autoload settings to "", or add namespace System; to your Test.php file. If you want to understand why it's acting like it is, you have to understand a bit about how autoloading works in PHP:
PHP lets you register an autoloader to find classes which haven't been encountered yet. The autoloader is handed a class name, and given a chance to find it. Usually they work by mapping class names to files in some way. When they're asked for an unknown class, they translate the class name to a file name, and try to require the file.
PSR-4 is a standard for setting up such an autoloader, and Composer comes with a PSR-4 compliant autoloader for free. For it to work right, you have to lay out your classes and namespaces like PSR-4 expects. If you don't, you can run into strange issues like you're encountering.
When you first tried calling Test::hello(), the class wasn't defined. Your PSR-4 autoloader translated that to a file name, but per your config, there's nowhere defined for non-namespaced classes to live, so it couldn't find a file to load, and it ended up loading nothing. After the autoloader had a chance, PHP still didn't know about that class, so it threw an error.
When you tried calling System\Test::hello(), your PSR-4 autoloader looked it up in the config and translated it to a filename (phpclasses/Test.php), which did exist this time, so it loaded that file. PHP then tried calling the method, but it didn't know about that class, so it threw an error.
The third time, it had already loaded your file and discovered the non-namespaced Test class. So when you tried calling it again, it didn't even bother with the autoloader, and just executed your method.
I have created a very basic validator class.
My base code is in a my src/ folder, which gets autoloader with
"kevdotbadger\\Validator\\": "src/"
this works fine, so that when I instantiate a new "kevdotbadger\Validator\ Validator is gives me src/Validator.php
My Validator.php class then loads a bunch of sub-classes in my src/Rules directory. These are magically loaded by using the __call, so ->between() should look for src/Rules/between.php. However, for some reason it won't usual load despite it being setup in my composer.json file.
My whole codebase is available at https://github.com/kevdotbadger/validator/
Have I setup my namespace correctly? I think the problem might be with php version 5.3, however I need to use version 5.3.
Thanks.
Well you need to keep the guidelines of psr-4 as you are using it to autoload.
change the folder name "rules" to "Rules"
Uppercase all your file names of classes like:
between.php --> Between.php
that should do the job
I've been building a web app of my own for a while now, but have completely hit against the wall with a fatal error in PHP.
Short story: I'm working on the login / user section of the project. login.php handles the login stuff, while student.php handles the account stuff.
When trying to complete doLogin, I achieve the fatal error that states student::getProfile() is an "undefined method". student::getProfile() is called as part of validate() inside the login class.
Any assistance would be greatly appreciated! Thanks :)
EDIT: With the help of #deceze I've been able to narrow the issue down to the fact that Composer isn't autoloading all of my classes; only some. Would anyone be able to assist?
EDIT 2: I checked autoload_classmap.php which was generated by Composer, and all my core classes and models are listed! If they're listed in the classmap, why isn't Composer loaded them?
project directory
application/
config/
controller/
core/
(core items such as auth, app, view rendering + view controller)
model/
(speciality functions such as login, registration + user)
view/
public/
index.php
.htaccess
vendor/
autoload.php
composer.json
.htaccess
note: /public/index.php calls `require '../vendor/autoload.php';`
composer.json
"autoload": {
"psr-4": {
"": [
"application/core/",
"application/model/"
]
}
}
After much tedious searching, I've found the error in my ways - and it's pretty silly!
I have a controller named student while also having a model named student, and as such I was inadvertently trying to call a class that's technically already being called. As such, it was looking in the first student class for the function, rather than the other which actually contained that specific function.
Composer doesn't realise if there is already a class with that name pre-declared, and just negates it without any entry in the PHP error log.
To avoid this error - and any further class name mixups in the future - I decided to use individual namespaces for both core classes and model classes. This separates those classes into 'sub-sections' as such, allowing the use of classes named the same (albeit in different namespaces).
PHP Manual: Namespaces
Sitepoint: How to Use PHP Namespaces, Part 1: The Basics
I'm a little unexperienced with composer and I'm starting to use Github more and more. I'm a php developer and I an application to serve as a CMS/Backoffice of the websites I develop to my clients.
I'm using and HMVC framework and I wanted to know if its possible o deploy a module (a repository) in a specific folder with composer, and again with composer change some lines of code.
For example, I have this structure:
- app
-- modules
--- users
--- auth
-- index.php
-- configs.php
- public
-- assets
In this example, users and auth are booth a module. Imagine that I have this repository in rafaelmsantos/posts and want to deploy it on the modules folder. That part I guess is simple, or its difficult?
The second part is the following: imagine that in posts repository I have a class file like this:
<?php
// $this->route('posts', 'postsController->action');
class PostsController extends appController{
function action(){
somestuff();
}
}
And when I deploy the module, I want the composer to read this file and detect that comment above class declaration and insert it into config.php that is in same level that modules folder.
Is this possible too?
Let me know some good tutorials for composer or something.
Thanks, in advance.
Composer have post-install-cmd and post-update-cmd events, which must be declared in composer.json file in scripts part.
For example:
{
"scripts": {
"post-update-cmd": "MyVendor\MyClass::postUpdate",
}
}
where 'postUpdate' is a static method, which add routes as you want.
Full info about scripts in composer
I created a modular system by using laravel 4.1 I have a tree scheme as follows:
app/
app/controllers/
app/modules/
app/modules/modulename/
app/modules/modulename/controllers/
app/modules/modulename/controllers/modulecontroller.php
app/modules/modulename/models/
app/modules/modulename/models/modulemodel.php
What I want to do is to call the model from a controller in app/controllers/ class.
How I can call that module and its model?
Make sure your /app/modules is added to your composer.json file's autoload : classmap and issue composer dump-autoload or php artisan dump-autoload. Then you can just create an instance like new ModuleModel or whatever name you gave your class. Though it's better to pass to your controller by dependency injection. This way your code will be easier to test because you can pass in stub data.
public function __construct(ModuleModel $module_model_instance) {
$this->module_model_instance = $module_model_instance;
}
I'd rather add this as a comment but have insufficient rep.
If everything is correctly autoloaded by composer in the PSR-0 (or 4) section, then you should just be able to reference it using it's namespace?
I sometimes need to run
composer dump-autoload
to refresh the autoloaded files, especially if using vagrant.
Hope this is helpful. I'm not sure if I've fully understood your problem.