autoloading nested classes with composer - php

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

Related

How to use one module in two different application/project in yii2

I have module created in the basic project of yii2 and now i want to access or use that module another project/application of mine....
How can I achieve this.
please help me out here.
To use module in different apps there are 3 things you need.
The module must not be dependent on classes from core project. For any class that needs to be implemented by core project the module should define interface and depend on that interface instead of class itself.
The module should use different namespace than app and autoloader must know how to load classes from that namespace. (more about that later)
You have to add module in your config in same way you've added it in first project.
The points 1 and 3 are pretty much self-explaining. If are not sure how to add module in config see the yii2 guide.
Now back to the second point. While naive way of copying module over to second project would work it will turn maintaining the module into nightmare because each change would have to be done in each copy of module. So it's better to keep the code of module in one place and make it available for each project. There are multiple ways of doing that.
If you want to, you can turn your module into extension and make it publicly available through packagist as it was suggested by M. Eriksson in comments. After that you would simply add your extension through composer as any other dependency.
Composer also allows you to define and use private repositories if you don't want to publish your module at packagist. See composer documentation for more details.
The most trivial way is to simply put the code into separate folder outside of project. If you do that, you have to make sure that autoloaders in your projects are capable of finding the files locations to load classes. There are two options how to do that. In any case you will want to avoid conflicts with namespaces used by your project, that's why you need to use different namespace.
Let's assume that you've put your module files into folder /path/to/modules/myModule and all classes in your module belongs to namespace modules\myModule. You have to make sure that your webserver can access that folder and that it can run php scripts there.
First option is to use Yii's autoloader. That autoloader uses aliases to look for classes. If you add #modules alias and point it to /path/to/modules folder, the Yii autoloader will try to look for any class from modules\* namespace in /path/to/modules folder. You can add the alias in your config file (web.php, console.php or any other config file you use):
return [
// ...
'aliases' => [
'#modules' => '/path/to/modules',
// ... other aliases ...
],
];
The second option is to use project's composer.json file to set autoloader generated by composer to load your classes.
{
"autoload": {
"psr-4": {
"modules\\": "/path/to/modules"
}
}
}
You can find more info about this in composer's documentation.
Don't forget to run composer dump-autoload after you change autoload settings in your composer.json file to update the generated autoloader.

Difficulty instantiating classes in psysh

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.

composer with files not using psr0 and psr4 autoloading (symfony project)

I have a problem with composer auto loader. Currently working on a application which was developed about 10 years back. The folder structure of 2 libraries which are currently used in the project do not comply the psr0 and psr4 auto loading rules.
The structure after the composer install looks as follows
Example 1
Folder path: /vendor/AppBook/ORS/class/model/Country
Filename: class.Country.php
PHP Class name: Country
Example 2
Folder path: /vendor/AppBook/ORS/class/model/Country
Filename: class.CountryCollection.php
PHP Class name: CountryCollection
Please advise what should I do in order that composer auto loader can detect these files.
Thank you in advance
From the docs:
You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4. To configure this you specify all directories or files to search for classes.
Example:
{
"autoload": {
"classmap": ["src/", "lib/", "Something.php"]
}
}
You can still add composer.json to your legacy libraries and define classmap autoloading type for them.
You can rename these files to make them compatible to PSR-4 (unlikely because that requires using namespaces - in 10 years old code?) or PSR-0. Additionally, you have to remove any explicit loading of these files via include, include_once, require or require_once because the file names changed.
PHP will autoload these classes by their class name. This will possibly run into issues if the case sensitivity in the class name is not respected everywhere. Example:
class UpperCase {}
$a = new upperCase();
The autoloading would try to find a file ending with upperCase.php, which will not match the PSR-0 required UpperCase.php, so the code will fail. However, this will work, making the situation not better:
class UpperCase {}
$b = new UpperCase();
$a = new upperCase();
The reason is that PHP treats class names case insensitive, so once a class is loaded, you can use any case in it's name. It is only the first occurrence in your code path that has to match. The problem is to be sure where this really is, so essentially it has to be correct everywhere.
Yes, the classmap feature is the easier way. But you'd still want to remove include/require calls to optimize the performance a bit, so you have to touch the code anyway. And despite it's age, it has to be maintained - so why not do it fully, switching to a well-known autoloading standard. It will help you in the long run when you have to maintain PSR-0/4 compatible classes and this old code in parallel.

How to load my own code into Laravel? Differences between those ways?

I'm kind of confused on how to load my own code (classes or just regular functions) into a Laravel app. I've seen this done in several ways:
Creating a folder inside the app directory (for example: app/libs) and add app_path().'/libs' to start/global.php
Add it into composer.json's "require"
Add "psr-0" into composer.json's "autoload" and add there the files
Add a My\Custom\Service\Provider into app/config/app.php's 'providers' and the alias for the facade
What's the difference between them? Why and when should I use any of those ways? Should I load a class, several .php files or simply the folder? Maybe reference those 3 things at the same time?
EDIT:
These are my guesses:
Option 2 is just for packages
Option 3 if you want to load every class inside a custom namespace declared within the new created folder (don't get why the "psr-0" instead of just adding it to "classmap")
Option 1 is the same as option 3, just handled by Laravel instead of Composer
You can reference a folder and it will load every class found inside, or you can reference a certain file and it will load the class found inside
About option 4:
If you want to use the facade anywhere on your code, and that will need the namespace added into composer.json
EDIT 2:
If you add them to "classmap":
"classmap": [
"app/libs"
]
every class from any namespace within files inside the app/libs folder, will be loaded
If you add them to "psr-0":
"psr-0": {
"Libs": "app/"
}
it will load every class within the Libs namespace inside the app/libs folder
Still not sure why/when to use service providers and aliases.
EDIT 3:
"psr-0" if I want to load a namespace that follows a folder structure (it won't load a class within a subnamespace if it doesn't match the folder structure)
"classmap" for "random" classes, functions... sort of "the rest"
you can load your own code 2 (maybe 3) ways in laravel.
use composer
use ClassLoader
Manual include or require anywhere
Option 2 is just for packages
yes, you're right.
Option 1 is the same as option 3, just handled by Laravel instead of
Composer
yes, you're right.
Option 3 if you want to load every class inside a custom namespace
declared within the new created folder (don't get why the "psr-0"
instead of just adding it to "classmap")
some packages or classes adhere psr-0 standard, the rest is not. psr-0 option is mapping namespace to directory. the classmap is mapping
the namespace to certain directory or file and used for the class that is not adhere psr-0 standard.
You can use the classmap generation support to define autoloading for all libraries that do not follow PSR-0/4.
If you want to use the facade anywhere on your code, and that will
need the namespace added into composer.json
nope, instead, you have to add class alias for the facade in app/config/app.php
if your code is just file, not a class, then use composer autoload files
if your code is class but not adhere psr-0/4 standard, use composer autoload classmap or just add the containing directory to app/start/global.php.
otherwise, use composer autoload psr-0 or psr-4.
in Laravel 4,I add all of my class in "mylibrary" folder.
Then at app/start/global.php , I add app_path().'/mylibrary',
ClassLoader::addDirectories(array(
app_path().'/commands',
app_path().'/controllers',
app_path().'/models',
app_path().'/database/seeds',
app_path().'/mylibrary',
));
Within mylibrary there is MyClass.php , within MyClass.php there is test_myfunction()
and at app/view/home.blade.php I add these code :
<?php
$FMyClass11 = new MyClass;
$just_test=($FMyClass1->test_myfunction());
?>
Hope it works for you. :)

How to autoload a custom class in Zend Framework 2?

I'm using zend framework2 skeleton, and I'm trying to add my own classes behind vendor folder. The problem is: I don't know how to prepare the classes to be loaded on demand (autoloaded) only when I'll instantiate one of them from any module.
I tried with the solution explained at: How to load a custom library in Zend Framework 2? , but I'm getting the same error:
Fatal error: Class 'myNamespace\myClass' not found in path\IndexController.php on line x
My question is: Where and how should I insert my own classes to be later used from my modules?
Firstly, if they are your own classes and directly related to the modules (i.e not some custom library you have written) then you are better off having them in the actual module, not in the vendor folder.
However, if you are trying to include your own library that you have written I'd suggest you consider storing this elsewhere and adding it as a dependancy via composer.
I don't recommend this but you should be able to get the autoloading working by using the psr0 autoloader built in to composer (assuming your classes follow psr0). Example composer.json config:
{
[...]
"autoload": {
"psr-0": {
"MyNameSpace": "path/to/root/src/directory"
}
}
[...]
}
I know its a bit old but i was facing the same issue so what i did was:
inside vendor folder i created a new folder and gave it the name of Custom. Inside that folder i added my class file (MyClass.php).
inside MyClass.php i added this line (namespace Zend\Custom;).
And inside my Controller at the top
use Zend\Custom\MyClass;
and within a method of that controller
$someVar = new MyClass();
$someVar->someClassMethod();
I hope this helps.

Categories