Gadgetto Posted April 23, 2020 Share Posted April 23, 2020 Hi there, i am looking for a good guide for the correct use of the WireClassLoader class within a module. The Informations that can be found on this topic are very sparse. I generally have little experience with PHP namespaces and have just started using them in SnipWire. For example, I had a look at the module "Sitemap" by Rockett:https://gitlab.com/rockettpw/seo/markup-sitemap/-/blob/master/MarkupSitemap.module.php Unfortunately I can't really figure it out either. Below is a short snippet from the original code. The questions I would like to ask: Doesn't the file need a namespace on top? In which namespace resides this class? (doesn't look like its the ProcessWire namespace?) What exactly does the addNamespace method do? Does it replace all the require_once directives? <?php // Require the classloaders wire('classLoader')->addNamespace('Thepixeldeveloper\Sitemap', __DIR__ . '/src/Sitemap'); wire('classLoader')->addNamespace('Rockett\Concerns', __DIR__ . '/src/Concerns'); wire('classLoader')->addNamespace('Rockett\Support', __DIR__ . '/src/Support'); use ProcessWire\Language; use ProcessWire\Page; use ProcessWire\WireException; use Rockett\Concerns; use Rockett\Support\ParseFloat; use Rockett\Support\ParseTimestamp; use Thepixeldeveloper\Sitemap\Drivers\XmlWriterDriver; use Thepixeldeveloper\Sitemap\Extensions\Link; use Thepixeldeveloper\Sitemap\Url; use Thepixeldeveloper\Sitemap\Urlset; class MarkupSitemap extends WireData implements Module { ... } Maybe someone could help me to understand this? Greetings, Martin Link to comment Share on other sites More sharing options...
kongondo Posted April 23, 2020 Share Posted April 23, 2020 To answer part of your questions 42 minutes ago, Gadgetto said: Doesn't the file need a namespace on top? In the example code you've shown, they are using the use operator so they don't need the namespace on top. The use operator is mainly used for giving aliases to names of classes. https://www.php.net/manual/en/language.namespaces.importing.php Link to comment Share on other sites More sharing options...
kongondo Posted April 23, 2020 Share Posted April 23, 2020 Not sure you've seen this in the docs ($classLoader) https://processwire.com/api/ref/wire-class-loader/ Link to comment Share on other sites More sharing options...
Gadgetto Posted April 23, 2020 Author Share Posted April 23, 2020 3 hours ago, kongondo said: Not sure you've seen this in the docs ($classLoader) https://processwire.com/api/ref/wire-class-loader/ I've read the API docs for classLoader, but this didn't help. No explanation, no sample code ... Link to comment Share on other sites More sharing options...
Gadgetto Posted April 23, 2020 Author Share Posted April 23, 2020 3 hours ago, kongondo said: To answer part of your questions In the example code you've shown, they are using the use operator so they don't need the namespace on top. The use operator is mainly used for giving aliases to names of classes. https://www.php.net/manual/en/language.namespaces.importing.php This would compile the file for PW 3.x or not? (seems to be an older project) Link to comment Share on other sites More sharing options...
Gadgetto Posted April 23, 2020 Author Share Posted April 23, 2020 If I understand this correctly: the classLoader is loading classes via spl_autoload_register with addNamespace you tell the classLoader which classes to load (properties: namespace + path to the class files) this makes manually including of all class files from a specific folder obsolete What I don't understand: wire('classLoader')->addNamespace('SnipWire\Helpers', dirname(__DIR__) . '/helpers'); Would this preload all class files from within the /helpers directory? I still don't get the real purpose. This is probably as I also don't exactly know how the composer autoloader works... Link to comment Share on other sites More sharing options...
kongondo Posted April 23, 2020 Share Posted April 23, 2020 5 hours ago, Gadgetto said: What exactly does the addNamespace method do? My understanding it is useful in cases where composer is not installed, in which case classes will be loaded from file paths. Link to comment Share on other sites More sharing options...
kongondo Posted April 23, 2020 Share Posted April 23, 2020 (edited) 1 hour ago, Gadgetto said: Would this preload all class files from within the /helpers directory? These two posts seems to suggest so. I haven't tried it myself. Maybe you can try and let us know ? Edited April 23, 2020 by kongondo Link to comment Share on other sites More sharing options...
MoritzLost Posted April 23, 2020 Share Posted April 23, 2020 I use the classLoader in my TrelloWire module, you can look at the source code here. As you can see, this adds the src directory inside the module files to the WireClassLoader as the location to look for classes inside the namespace ProcessWire\TrelloWire. Quote Would this preload all class files from within the /helpers directory? Almost; it doesn't preload the classes, but only on demand. This way, once I instantiate the class ProcessWire\TrelloWire\TrelloWireApi, the WireClassLoader looks for the PHP file for this class inside the src directory (the one registered for that namespace through addNamespace). If it couldn't find it, an error would be thrown. (If you're wondering why I don't use the fully qualified namespace, note the use statement at the top). Quote I still don't get the real purpose. This is probably as I also don't exactly know how the composer autoloader works... Two main advantages: Using an autoloader, you can map classes to directories. The exact mapping (how namespaces are resolved to file paths) is defined in the PSR-4 standard. As far as I know, the WireClassLoader loosely complies with that. Composer mostly does the same thing (although a bit more elaborate, with optimizations for production usage etc.). Basically, you have a root directory mapped to a root namespace (in this case ProcessWire\TrelloWire -> src/ directory), and from there resolve sub-namespaces to sub-directories and the class name to a file name (so ProcessWire\TrelloWire\TrelloWireApi -> src/TrelloWireApi.php). The advantage is that you add namespaces wholesale. So you only need to add the mapping for the root namespace, and can then add as many classes and nested namespaces and classes without having to worry about including any class files manually because they will be autoloaded. Because class files are only included on-demand, only the classes you actually need for a request will be loaded. This of course cuts down on processing time, since otherwise you'd usually include all classes at the top for every request. Hope this clears up some of the confusion! 9 1 Link to comment Share on other sites More sharing options...
kongondo Posted April 23, 2020 Share Posted April 23, 2020 (edited) 1 hour ago, MoritzLost said: Because class files are only included on-demand, only the classes you actually need for a request will be loaded. This of course cuts down on processing time, since otherwise you'd usually include all classes at the top for every request. @MoritzLost: Is this true for Composer as well? Thanks for the write-up. Edited April 23, 2020 by kongondo Link to comment Share on other sites More sharing options...
Gadgetto Posted April 24, 2020 Author Share Posted April 24, 2020 11 hours ago, MoritzLost said: I use the classLoader in my TrelloWire module, you can look at the source code here. As you can see, this adds the src directory inside the module files to the WireClassLoader as the location to look for classes inside the namespace ProcessWire\TrelloWire. Almost; it doesn't preload the classes, but only on demand. This way, once I instantiate the class ProcessWire\TrelloWire\TrelloWireApi, the WireClassLoader looks for the PHP file for this class inside the src directory (the one registered for that namespace through addNamespace). If it couldn't find it, an error would be thrown. (If you're wondering why I don't use the fully qualified namespace, note the use statement at the top). Two main advantages: Using an autoloader, you can map classes to directories. The exact mapping (how namespaces are resolved to file paths) is defined in the PSR-4 standard. As far as I know, the WireClassLoader loosely complies with that. Composer mostly does the same thing (although a bit more elaborate, with optimizations for production usage etc.). Basically, you have a root directory mapped to a root namespace (in this case ProcessWire\TrelloWire -> src/ directory), and from there resolve sub-namespaces to sub-directories and the class name to a file name (so ProcessWire\TrelloWire\TrelloWireApi -> src/TrelloWireApi.php). The advantage is that you add namespaces wholesale. So you only need to add the mapping for the root namespace, and can then add as many classes and nested namespaces and classes without having to worry about including any class files manually because they will be autoloaded. Because class files are only included on-demand, only the classes you actually need for a request will be loaded. This of course cuts down on processing time, since otherwise you'd usually include all classes at the top for every request. Hope this clears up some of the confusion! Thanks a lot @MoritzLost! Link to comment Share on other sites More sharing options...
Gadgetto Posted April 24, 2020 Author Share Posted April 24, 2020 12 hours ago, MoritzLost said: If you're wondering why I don't use the fully qualified namespace, note the use statement at the top I see you put TrelloWire within the namespace of ProcessWire. Is there any benefit or is that just a matter of taste? 1 Link to comment Share on other sites More sharing options...
MoritzLost Posted April 24, 2020 Share Posted April 24, 2020 14 hours ago, kongondo said: Is this true for Composer as well? Yes, in general all autoloaders work this way. Composer just generates a file that registers an autoloader function through spl_autoload_register. This function is then called whenever a class is used that is not loaded yet, as a last chance to load the class before an error is thrown. Composer has a few different ways of locating the class files though. You can even generate an optimized autoloader that includes a class map which will speed up autoloading a bit. You can also test if a class is loaded already or autoloaded with class_exists: // using class_exists with false as the second argument, the autoloader will not be called // this return false for all classes that have not been manually included or autoloaded yet var_dump(class_exists('Some\Vendor\Class', false)); // this will trigger the autoloader, so even if the previous call returned false this will return true if the class exists var_dump(class_exists('Some\Vendor\Class')); I have a bit more information on Composer usage in my Composer for ProcessWire tutorial ? 3 hours ago, Gadgetto said: I see you put TrelloWire within the namespace of ProcessWire. Is there any benefit or is that just a matter of taste? Personal preference! I do believe that the .module files themselves need to be inside the ProcessWire namespace in order for ProcessWire to correctly load them in all situations. But ProcessWire doesn't know about the files in the src directory, so I could use any namespace I wanted (for Composer libraries, you'd usually use the developer / organization name as the top-level namespace, so I might have used something like MoritzLost\TrelloWire). It just felt wrong to me to have the main module files inside the ProcessWire namespace and the API in an entirely different namespace, this is why I used ProcessWire\TrelloWire. 4 Link to comment Share on other sites More sharing options...
kongondo Posted April 24, 2020 Share Posted April 24, 2020 11 minutes ago, MoritzLost said: I have a bit more information on Composer usage in my Composer for ProcessWire tutorial ? I'd totally forgotten about this one ?. Thanks for the reminder. Link to comment Share on other sites More sharing options...
kongondo Posted April 29, 2020 Share Posted April 29, 2020 @Gadgetto Moderator note: I have split this thread. It is advised to start new topics for questions that are not directly relevant to the existing topic. The new topic is here: Link to comment Share on other sites More sharing options...
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