CakePHP 4 custom plugin dont find classes - php

I try to create a Custom Plugin for CakePHP 4. But everytime i become a error that the plugin cant find the classes of the plugin.
I load the plugin in the Application.php
use Wirecore\CakePHP_JWT\Plugin as CakePHPJwt;
$plugin = new CakePHPJwt();
$this->addPlugin($plugin);
In the composer.json file of cake its also loaded:
"autoload": {
"psr-4": {
"App\\": "src/",
"Wirecore\\CakePHP_JWT\\": "./plugins/CakePHP-JWT-Plugin/src/"
}
},
"autoload-dev": {
"psr-4": {
"App\\Test\\": "tests/",
"Cake\\Test\\": "vendor/cakephp/cakephp/tests/",
"Wirecore\\CakePHP_JWT\\Test\\": "./plugins/CakePHP-JWT-Plugin/tests/"
}
}
and i create a file in /plugins/CakePHP-JWT-Plugin/src/Middleware/JwtMiddleware.php with example code of the documentation Middleware. I changed the namespace of the example code to
namespace Wirecore\CakePHP_JWT\Middleware;
after this i try to load the middle in the middleware function of the plugin but everytime i become this error:
Class 'Wirecore\CakePHP_JWT\Middleware\TrackingCookieMiddleware' not found
here the code of the middleware function:
use Wirecore\CakePHP_JWT\Middleware\TrackingCookieMiddleware;
$middlewareQueue->add(new TrackingCookieMiddleware());
return $middlewareQueue;
i have tried to change the namespace but it does not work, and i try it with composer dumpautoload but again it changed nothing. Any ideas ?

The autoload section in the composer file is what tells PHP how to find your namespaces on disk. Your namespace prefix for the class, Wirecore\CakePHP_JWT, is not the namespace you listed in the autoload section, you listed Wirecore\CakePHP-JWT-Plugin. Either fix the namespace declaration to match autoload, like so:
use Wirecore\CakePHP-JWT-Plugin\ .. etc
.. or change fix the autoload section to match the name listed in your namespace declaration:
"autoload": {
"psr-4": {
"Wirecore\\CakePHP_JWT\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Wirecore\\CakePHP_JWT\\Test\\": "tests/",
"Cake\\Test\\": "vendor/cakephp/cakephp/tests/"
}
}
Also, I'm not positive what standards your following here, but they potentially don't look right.
Is this a standalone plugin? If so, I'd mirror the structure from another standalone plugin like https://github.com/dereuromark/cakephp-geo/
If this isn't a standalone plugin (which is what seems more probable), but just a custom plugin being put directly into an existing CakePHP app, you're classes should be stuck in /plugins not /src, per the docs https://book.cakephp.org/4/en/plugins.html#creating-your-own-plugins
You might want to just use the Bake utility as a starting point (that'll solve your autoload issues too!) and copy your code into the classes it creates instead.

Related

Class not in namespace

I am trying to create a hook extension for Contao.
But Contao doesn't seem to be able to load my class from the namespace, which handles the hook.
This is my file structure:
I have tried changing names and added ".php" to the class, looked up tutorials, but I can't find what I am doing wrong. I am fairly inexperienced in this topic, so I might be missing something obvious.
autoload.php
ClassLoader::addNamespaces(array
(
'Memberlevels',
));
gister PSR-0 namespace
*/
if (class_exists('NamespaceClassLoader')) {
NamespaceClassLoader::add('Memberlevels', 'system/modules/memberlevels/classes');
}
if (class_exists('NamespaceClassLoader')) {
NamespaceClassLoader::addClassMap(array
(
'Memberlevels' => 'system/modules/memberlevels/classes/myClass.php'
));
}
/*
* Register the templates
*/
TemplateLoader::addFiles([
'cookiebar' => 'system/modules/memberlevels/templates',
]);
config.php
$GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = array('Memberlevels\myClass', 'myOutputBackendTemplate');
I get the error message:
Attempted to load class "myClass" from namespace "Memberlevels". Did you forget a "use" statement for another namespace?
You are still using the old Contao 3 way of loading classes. In Contao 4, you should use the autoloading feature of composer. The default composer.json of the most recent Contao versions already include autoloading directives for the src/ folder of your Contao installation:
"autoload": {
"psr-4": {
"App\\": "src/"
}
},
Using that, this is how you create & register a hook in a Contao 4.4 compatible way:
// src/EventListener/OutputBackendTemplateListener.php
namespace App\EventListener;
class OutputBackendTemplateListener
{
public function onOutputBackendTemplate(string $buffer, string $template): string
{
// Do something
return $buffer;
}
}
// app/Resources/contao/config/config.php
$GLOBALS['TL_HOOKS']['outputBackendTemplate'][] = [\App\EventListener\OutputBackendTemplateListener::class, 'onOutputBackendTemplate'];
Starting with Contao 4.8 you can also use annotations to register a hook, eliminating the need to register the hook in app/Resources/contao/config/config.php.

Autoload PSR-4 Specific Class

I have autoload setup via PSR-4 which works perfectly fine. However I want to be able to add a specific class on top of that, that I can access from anywhere in the application.
This is what I have currently:
"autoload": {
"psr-4": {
"App\\": "app"
}
}
However I want to add a class called 'Redis' which is located in app/Lib/Redis.php so that from any Controller I can call Redis::method(); without having to add 'use App\Lib\Redis;' to the top of each file.
Is this possible?
This can't be done directly.
You could create a global function redis() and register than with composer:
"autoload": {
"psr-4": {
"App\\": "app"
},
"files"" {
"app/functions.php",
}
}
If this redis() function returned an instance of your Redis class, then I think that you could then do:
redis()->method();
Whether you should do this or not is another matter - unit testing becomes highly problematic. Personally, I would have a use statement and inject an instance of the Redis object into the constructors of the classes that need it.

Composer autoload not including my custom namespaces (Silex)

I'm developing a REST API with Silex and I'm facing a problem regarding autoloading of my custom librairy. It looks like Composer's autoload is not including it, because when I include it myself it works.
# The autoload section in composer.json
# Tried with :
# "Oc\\": "src/Oc"
# "Oc\\": "src/"
# "": "src/"
"autoload": {
"psr-4": {
"Oc\\": "src/"
}
}
<?php
// api/index.php <-- public-facing API
require_once __DIR__.'/../vendor/autoload.php';
$app = require __DIR__.'/../src/app.php';
require __DIR__.'/../src/routes.php'; // <--
$app->run();
<?php
// src/routes.php
// When uncommented, it works!
//include('Oc/ParseImport.php');
use Symfony\Component\HttpFoundation\Response;
use Oc\ParseImport;
$app->get('/hello', function () use ($app) {
return new Response(Oc\ParseImport(), 200);
});
<?php
// src/Oc/ParseImport.php
namespace Oc {
function ParseImport() {
return 'foobar!';
}
}
I run composer dumpautoload after each composer.json manipulation, and I do see the line 'Oc\\' => array($baseDir . '/src/Oc') (or anything I tried) in vendor/composer/autoload_psr4.php.
I can't figure out what is wrong.
Almost everything you did was correct.
When trying to autoload classes in a namespace, given that a class is named Oc\Foo and is located in the file src/Oc/Foo.php, the correct autoloading would be "PSR-4": { "Oc\\": "src/Oc" }.
However, you do not have a class. You have a function. And functions cannot be autoloaded by PHP until now. It has been proposed more than once (the one proposal I found easily is https://wiki.php.net/rfc/function_autoloading), but until now this feature hasn't been implemented.
Your alternative solutions:
Move the function into a static method of a class. Classes can be autoloaded.
Include the function definition as "files" autoloading: "files": ["src/Oc/ParseImport.php"] Note that this approach will always include that file even if it isn't being used - but there is no other way to include functions in PHP.
As illustration see how Guzzle did it:
Autoloading in composer.json
Conditional include of functions based on function_exists
Function definition

Custom class in laravel is not being recognized

So I've been trying to create a custom class file for all my custom classes and append them in there, I'm using namespaces in order to accomplish using them in my controller however the controller is not recognizing the class
Ok:
Here is my custom class file placed in my project as app/Library/robloxClasses.php
namespace App\Library;
class RobloxMaths{
public function sortArrayOfArray(&$array, $subfield)
{
$sortarray = array();
foreach ($array as $key => $row)
{
$sortarray[$key] = $row[$subfield];
}
array_multisort($sortarray, SORT_DESC, $array);
}
}
Library is a folder i made to store all my custom class files in there
Here is how my controller ApiController uses the file using it's namespace
<?php
namespace App\Http\Controllers;
use App\Library\RobloxMaths;
use Illuminate\Http\Request;
class ApiController extends Controller
{
protected $RobloxClass;
public function __construct(){
$this->$RobloxClass= new RobloxMaths;
}
}
?>
The problem is, it keeps returning:
Class 'App\Library\RobloxMaths' not found
And I honestly do not know what's wrong, please help!
NOTE: I have tried composer update, and it fixes it temporarily but after a day or two or after me installing new dependencies it notifies me that the Class 'App\Library\RobloxMaths' not found thing happened
help please
Ensure that you have correctly setup the psr-4 autoload root in your composer.json file and that your file/directory names match perfectly including capitalisation, then run composer dump-autoload.
Example:
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
This will assign the root namespace App to the app folder.
If you are using an IDE, there is a large chance that your use and namespace statements where auto-generated with the lowercase app to match the directory name. As all the names tie up correctly in the IDE there are no errors, but when it comes to running the PHP script the autoloader is not doing require|require_once on your files and therefore your classes are not available.
Option 1 (Do this)
Ensure that your namespaces have consistent capitalisation that matches the composer.json entry.
Option 2 (Written for completion)
Ensure that you add a new entry for this root namespace to your composer.json file. For the example above this would be:
"autoload": {
"psr-4": {
"App\\": "app/",
"app\\": "app/"
}
}
It's an old question, but I had the same problem with laravel 9,
The problem is that I've used php short tag <? instead of <?php at the custom class file.
it's silly but this was the solution for me.

"Class not found" What did I miss?

I want to add Accessors and Mutators to a model. In Laravel 4 it worked all fine, but with Laravel 5 I have some trouble.
I have a "lib" folder in my App directory which contains the "db_transformers.php" file. This file holds classes like "dbDate" with a set and get function to transform dates stored in the database to a user-friendly format.
The "db_transformers.php" file is namespaced:
<?php namespace App\lib;
I also rerfer to the folder in my model:
use App\lib;
But my methodes still throw errors:
public function getDateTimeAttribute($value)
{
return dbDate::get($value);
}
This will return a "Class 'App\dbDate' not found" error.
What could be my problem?
You're confusing autoloading (PHP including/requiring a class definition file) with namespaces (a system that allows hierarchical naming of PHP classes/functions to help prevent code conflicts).
It's an easy thing to do. Covering the changes to autoloading in Laravel 5 is beyond the scope of a Stack Overflow question, but if you're interested I've written a multiple article series on how autoloading works with composer/Laravel 4/Laravel 5.
To your specific question, you say you've defined a class named dbDate in a file named db_transformers.php, and db_transformers.php has a namespace of App\lib.
#File: lib/db_transformers.php
namespace App\lib;
//other code
class dbDate
{
//other code
}
//other code
This mean your class's full name is App\lib\dbDate. The entire thing is the class's name. That's probably the biggest thing to get used to with namespaces in PHP.
This means if you wanted to use the class in other code, you'd need to refer to the full class name, including a leading backslash.
return \App\lib\DbDate::get($value);
You could also import the class using the use keyword
use App\lib\DbDate;
//other code
public function getDateTimeAttribute($value)
{
//since we imported the class with `use`, we don't need to type the full name
return DbDate::get($value);
}
The use keywords imports a specific class into the current namespace. When you said
use App\lib;
you were telling PHP
You know that global classApp\lib? I'm going to refer to it below as lib
Since you don't have a class named lib, this is meaningless, and it's why your use didn't help.
So that's namespaces. The other problem you need to solve is autoloading. Autoloading is what lets you skip the require or include statement/function when you want a class definition files in your project.
Laravel 4 used a bunch of different autoloaders, including something called a classmap autoloader. The classmap autoloader automatically parses all the files in your project looking for classes, and creates a giant map of which class is where (that's over simplifying it a bit, see the article series I linked earlier for the full details).
In Laravel 4, the classmap autoloader probably read the file in lib for you. Laravel 5 reduced the number of autoloaders, which included getting rid of the classmap autoloader for most folders.
The simplest thing you can do in Laravel 5 is to configure your project to use the classmap autoloader again. Open up composer.json and find this section
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
}
},
And add lib to the classmap autoloader section
"autoload": {
"classmap": [
"database",
"lib"
],
"psr-4": {
"App\\": "app/"
}
},
This tells composer to include the lib folders when it creates its autoloader files. You'll need to run the dumpautoload command
composer dump-autoload
after doing that, and you should be able to use the classes defined in lib/db_transformers.php as you wish.
You need to use the complete class name: use App\lib\dbDate;
You might also look into using view decorators for this purpose, as doing it in your model is really not appropriate.
Several packages exist to help with this, e.g. https://github.com/ShawnMcCool/laravel-auto-presenter

Categories