TomPich Posted September 14, 2024 Posted September 14, 2024 Hi guys, I know this has been asked already a few times here, but I couldn’t find a working solution for me... Working on a quite big project and I feel it can get messy quite easily. I need to tidy my code a little but. So here is the situation: I have quite a lot of data handling to do in the front side of my website. This involves querying on an external DB and processing the data. I started to write some methods in a DefaultPage class and that works well, but this will end with a very big file with tens of methods not related to the same logic. What I would like, is to have a src/ folder in my site/ folder, with all the custom classes in relevant subfolders. I tried this: // in site/init.php $namespace = 'ProcessWire\\App'; $classLoader = $this->wire('classLoader'); if (!$classLoader->hasNamespace($namespace)) { $srcPath = 'src/'; // target folder is /site/src $classLoader->addNamespace($namespace, $srcPath); } Inside this site/src/ folder, there is a MyClass.php file, with the class MyClass namespace App; class MyClass { const hello = "hello"; } And in my template file: namespace ProcessWire; use App\MyClass; <?= MyClass::hello ?> But I can’t get class loaded... 😔 I tried variation with namespace and use, but it didn’t work... Any help please ? Thank you!
da² Posted September 14, 2024 Posted September 14, 2024 (edited) Hi, I tried the same a while ago and it appears PW is forcing custom classes to be in site/classes directory. The code seems to be in ProcessWire.php: $cfg['paths']->data('classes', $cfg['paths']->site . "classes/"); Maybe you can overwrite this in your own config.php? Not sure if this is a good idea. ^^ But these classes dependencies can be in any package in site/templates/YourPackage (parent/abstract classes, Traits...). On my side the code I put in page classes is only related to the model part (getting/setting data), I don't use them to do rendering or controller stuff. The main part of the code is in my packages in site/templates. So I'm not really annoyed by the fact they have to be in the same directory, but I admit it would be better to put them in their related package. Edited September 14, 2024 by da² 1
fliwire Posted September 14, 2024 Posted September 14, 2024 <?php // site/init.php namespace ProcessWire; if (!defined("PROCESSWIRE")) die(); $classLoader = $wire->classLoader; $classLoader->addSuffix("Service", __DIR__ . '/services'); $classLoader->addSuffix("Form", __DIR__ . '/forms'); $classLoader->addNamespace("ProcessWire", __DIR__ . '/utils'); 2 1
TomPich Posted September 15, 2024 Author Posted September 15, 2024 Hey guys, @da², @fliwire, thank you for your help. It pushed me in the right direction. I got my things done and wanted to share with whoever would find that useful. Here was my need: a specific folder to store some classes, usable easily across templates (ie "use Class" and not "include ...". These classes wouldn’t fit (IMO) into a DefaultPage class for separation of concerns matter. And I didn’t want to try to develop a module, seemed an overkill and time is running... I decided to store my custom classes files into some subfolders of the /site/classes folder. At first, I used a /site/src folder (and it worked), but as the classes folder already exists, I thought it made more sense to use this folder. This is my architecture ├── site/ │ ├── assets │ ├── classes/ │ │ ├── Repository/ │ │ │ ├── AbstractRepository.php │ │ │ └── ContactRepository.php │ │ ├── DefaultPage.php │ │ ├── HomePage.php │ │ └── Utils.php │ ├── modules │ └── templates └── wire For autoloading use PW autoloader, in put in init.php $classLoader = $wire->classLoader; $classLoader->addNamespace("ProcessWire", __DIR__ . '/classes'); Then the magic happens. My ContactRepository.php, for example : namespace ProcessWire\Repository; use ProcessWire\Utils; class ContactRepository extends AbstractRepository { // my stuff here... } and when I need it in a template file : namespace ProcessWire; use ProcessWire\Repository\ContactRepository; $contactRepo = new ContactRepository; $speakers = $contactRepo->getAllSpeakersAndModerators(); Remarque: In the init.php file, I tried with and without $classLoader->addSuffix("Repo", __DIR__ . '/classes/repositories'); // does not change anything $classLoader->addPrefix("Repo", __DIR__ . '/classes/repositories'); // does not change anything I can't really grasp in which situation this useful, and the doc is quite short... 😅 So with this file structure, I can really get a step further in logic handling and code maintenance. Hope someone will find this useful. Cheers 4
da² Posted September 15, 2024 Posted September 15, 2024 I don't understand why this is necessary: $classLoader->addNamespace("ProcessWire", __DIR__ . '/classes'); I don't need this to get auto-load of custom classes.
TomPich Posted September 15, 2024 Author Posted September 15, 2024 If I don’t use it, ProcessWire is apparently not able to import classes in the Repository Subfolder
szabesz Posted September 15, 2024 Posted September 15, 2024 4 hours ago, TomPich said: For autoloading use PW autoloader, in put in init.php $classLoader = $wire->classLoader; $classLoader->addNamespace("ProcessWire", __DIR__ . '/classes'); If you need to do it even earlier than using init.php: https://processwire.com/talk/topic/26875-page-classes-with-traits/?do=findComment&comment=222333 also see: https://github.com/processwire/processwire/blob/3cc76cc886a49313b4bfb9a1a904bd88d11b7cb7/wire/config.php#L1756 1
da² Posted September 15, 2024 Posted September 15, 2024 (edited) 1 hour ago, TomPich said: If I don’t use it, ProcessWire is apparently not able to import classes in the Repository Subfolder Hmm, I don't need it on my side. Are you using the correct namespace? I added a directory Test in site/classes/, inside a class Foo with this namespace: <?php namespace ProcessWire\Test; class Foo{} And in a template.php I instanciate it: use ProcessWire\Test\Foo; $test = new Foo(); If you're using the same code, maybe it comes from my composer.json but I would be surprised. I updated the composer.json, but only to add my own namespaces. ** looking my composer.json and... Hoooooo yes I know why... 😁 ** "autoload": { "files": [ "wire/core/ProcessWire.php" ], "psr-4": { "Rfro\\Rfrorga\\ProcessWire\\": "site/templates/", "ProcessWire\\": "site/classes/", "Rfro\\Rfrorga\\WebApi\\": "webApi/", "Rfro\\Rfrorga\\Cron\\": "cron/" } }, I don't remember why but I added a namespace for site/classes. 🤔 Probably for the same problem as you... Could it be a cleaner way to solve your issue? Edited September 15, 2024 by da² 2
fliwire Posted September 15, 2024 Posted September 15, 2024 @TomPich // suffix is Repository not Repo. $classLoader->addSuffix("Repository", __DIR__ . '/classes/Repository');
TomPich Posted September 16, 2024 Author Posted September 16, 2024 9 hours ago, fliwire said: // suffix is Repository not Repo. $classLoader->addSuffix("Repository", __DIR__ . '/classes/Repository'); Yes... I tried Repository first, then I tested with another suffix (Repo), and it didn’t change anything (and I then commented it out...). The addnamespace does all the job. So I don’t get what this addSuffix does. My guess is that it allows better performance when there are a lot of classes, pointing out the sub-folder to look into. But then, so does the namespace ProcessWire\Repository; I can't figure it out...
fliwire Posted September 16, 2024 Posted September 16, 2024 (edited) addSuffix loads class if filename ends with suffix. processwire/wire/core/ProcessWire.php at 3cc76cc886a49313b4bfb9a1a904bd88d11b7cb7 · processwire/processwire (github.com) my setup. changed default "classes" dir with "models". Edited September 16, 2024 by fliwire 2 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now