Jump to content

2.4 Development Questions


Recommended Posts

Now that 2.3 has been finished, when will you (Ryan) start developing 2.4?

According to the roadmap 2.4 will port the hole system to PHP 5.3+ which I think is great.

It says we'll get namespaces, PSR-0 and PSR-1 support. What exactly does it mean? Will it use Composer? I really think it should as it's the greatest asset for the future of PHP. We could keep the framework seperate so that others can use it (http://processwire.com/talk/topic/818-currentformer-textpattern-users-what-do-you-think-txp5-using-pw/).

I'd also like if PW used some proved libraries from (for example) Symfony (http://symfony.com/components) or Laravel (http://github.com/illuminate). Maybe because I'd love a "Processwire on Laravel (Components) with Craft-like design" ;)

Just interested in how Ryan is going to make PW adopt 5.3, PSR + Composer will push PHP in the future and there are great libraries that are well (unit-)tested and could be used.

Link to comment
Share on other sites

Sessions, cookies, hashing, routing, HTTP handling, cache, database, IoC, logging (PSR-3 valid) and so on .. There are so many great things you could use :) This would also give you the way to adopt new great concepts like IoC which allow to write ways more/ better testable code.

Link to comment
Share on other sites

Just a suggestion :) Even if we keep the code it would be good to Unit test the core and make the framework available on composer. Though interested in what Ryan says.

Suggestions are very much welcome and I'd like to hear what Ryan thinks about this too. On the other hand, like @WillyC pointed out above, PW does many - if not all - of the things you've mentioned here very well and still has a lot of potential to grow and evolve.

The way I see it, being geared towards slightly more specific needs than other popular frameworks (namely content management) allows PW to focus on what's really important there instead of trying to become everything for everyone. Don't get me wrong, though - I'm not saying that all other frameworks are somehow chaotic. I'm sure they all have their strong points and specialties, my point is that so does PW.

Anyway, there have been discussions about integrating other libraries with PW around here and some people still use things like Flourish for certain tasks. I've personally used parts of Zend Framework in the past, but these days I seem to find very few reasons for that anymore, except for certain very specific things. PW is flexible enough to let you work exactly how you prefer and if you prefer to use other tools for some tasks there's nothing stopping you (even if those aren't bundled with PW code.)

Last but not least I'd like to point out that unit tests for core code are on their way. Don't worry, we'll get there :)

Edit: Forgot to mention that I'm not (yet) familiar with Composer, though it does sound interesting. Will have to take a closer look. Thanks for the tip!

Edited by teppo
  • Like 4
Link to comment
Share on other sites

Now that 2.3 has been finished, when will you (Ryan) start developing 2.4?

Once the multi-language page names module is stable and in production use. So will probably start developing the namespaces stuff in May. 

It says we'll get namespaces, PSR-0 and PSR-1 support. What exactly does it mean? Will it use Composer? I really think it should as it's the greatest asset for the future of PHP.

Namespaces are the primary aim, with PSR-0 being a natural extension of that. I plan to shoot for PSR-1 too if it looks like it'll benefit our audience. Also as a natural extension to these updates, I am interested in supporting Composer, and will do so if possible. I agree it's a great asset for PHP, though am less certain if it's as much of a draw for ProcessWire's primary audience. Throughout all of these 2.4 updates, I feel a lot of care will have to be taken to balance these updates with other improvements to the system. After all, our audience is primarily web designers and developers, and less purely PHP coders. I think a majority of our users doesn't actually care about namespaces, PSR standards and Composer, so I don't want to get too far off track, even if I personally have a strong desire for these things. But the driving aim of 2.4 is to help ProcessWire benefit from PHP 5.3+ as much as possible. This likely includes all of the things outlined. 

We could keep the framework seperate so that others can use it

I've always been interested in this. PW started as just the content framework, and underneath it still is. I'd like to retain and reinforce those roots. But don't think I want to actively maintain PW as two projects until there is real need for it (just as a matter of resources). 

I'd also like if PW used some proved libraries from (for example) Symfony (http://symfony.com/components) or Laravel (http://github.com/illuminate).

I'd like to make it easy for people to integrate components if they want to, and I think Composer is probably the way to do that. But don't currently see a need for any of our core components to come from another framework. Though I'm always open to the idea if there is a real benefit to our users. 

This would also give you the way to adopt new great concepts like IoC which allow to write ways more/ better testable code.

IoC is not a new concept. :) ProcessWire was written with an emphasis on best practices, patterns and concepts like this, everywhere beneficial to the project goals. 

Even if we keep the code it would be good to Unit test the core and make the framework available on composer.

The primary need for unit tests in PW has been with the selector engine, both DB and in-memory, and the consistency of the two. Luckily this is an active project, and it has already been hugely helpful and influential in ProcessWire 2.3 (thanks to Nik). In fact, I would probably consider the issues discovered and resulting solutions the most important upgrade to come with ProcessWire 2.3. 

  • Like 7
Link to comment
Share on other sites

Speaking of fortrabbit. I already emailed them telling about the change that has to be done on pw's .htaccess to install it there, and they answered that they will make sure to include pw specific insructions on their new docs. 

Link to comment
Share on other sites

Thanks for your answers! I think I like the idea of using popular packages because I do quite a lot of PHP dev using Laravel .. The current way seems pretty much convincing and right for PW.


Well, I don't know. But people love it (IoC) at the moment ;) Two projects? You could keep it the way it is and just split it (https://help.github.com/articles/splitting-a-subpath-out-into-a-new-repo). But I don't know how you would publish just the framework :)

Link to comment
Share on other sites

  • 3 weeks later...

Hello all, first post, nice to be here. Thanks for Processwire.

@ryan How are you thinking of going about namespacing and autoloading in Processwire? Isn't having the Wire class being the mother of all classes making this tricky?

While you are on the standards issue, why not go for PSR-2 too ? Common coding style would benefit everyone.

Link to comment
Share on other sites

I like and support code standards, especially the PSR ones. PSR-0 and PSR-1 affect the external use of your code, and provide consistency in how people access your code from the outside. I think these are important standards and am very enthusiastic about them for the most part. 

PSR-2 is not in the same class. It's a good standard, but is more about internal style than external access. It's one of a few good standards to consider if you are starting something new, especially with a team. 

But if a project has already adopted a style standard, it would be silly to change from one good style standard to another. The point of standards is unchanging consistency. Changing style standards is counter to the purpose of style standards. I don't think the committee behind PSR-2 would suggest changing from another good style standard to PSR-2. But I do think they would suggest PSR-2 as a solid style standard for new projects, and I would agree.

However, PSR-2 is not a clear choice even for new projects. It is somewhat controversial in that it's leaderless committee-design, full of compromises making concessions to differing opinions that don't usually go together. I think the committee-design is apparent in the resulting code style. I'm sure the folks behind it would agree and admit it is a lot of compromise. In this respect, I think it may be weaker than some other style standards, but that's always subjective. However, to focus on how or where it was designed is to ignore the point of the standard. So I very much respect what they were trying to do and have done.

I hope that PSR-2 will survive because I think the intentions are good. Though I'm not confident it will be so common 5 years from now. But I think PSR-0 and PSR-1 are here to stay. I hope that folks can understand why it would be a counterproductive (even disrespectful to the purpose of standards) for an established project to change from one internal style standard to another.

  • Like 1
Link to comment
Share on other sites

Yes I too believe that the intentions behind the PSR-2 are good mainly because it is a good thing to have if there are PSR-0 and PSR-1 standards in-place that promote code segmentation and proper focusing on the parts of the libraries. I am sad about PSR-2 being basically turned down in Processwire because having to deal with more than one source base (I am an avid open source stalker and minor contributor) hinders the ability to contribute by having another layer of adjustment before I get to see what is going on, that being the visual aspect of the code.

But my main question was about how you think that namespaces in Processwire will be structured? Are there going to be big changes? Anything the community can help with?

Link to comment
Share on other sites

I am sad about PSR-2 being basically turned down in Processwire because having to deal with more than one source base (I am an avid open source stalker and minor contributor) hinders the ability to contribute by having another layer of adjustment before I get to see what is going on, that being the visual aspect of the code.

I understand. Well the good thing is that our code standards are mostly similar to PSR-2, without some of the oddities it has (though I suppose that's subjective). I've found that I can go to/from PW <-> PSR-2 largely with simple search/replace, so I have no problem if people submit PSR-2 code. One of the nice things about code standards is that they are generally consistent and predictable, so going between different standards is not difficult. 

But my main question was about how you think that namespaces in Processwire will be structured? Are there going to be big changes? Anything the community can help with?

Thanks for your interest in this. I haven't yet started here, though know that mindplay.dk has done some work in this area and ProcessWire. Ultimately I want to gain the benefits of namespaces in PW without changing the way that people use the API. If people have to \Start\Doing\Lots\Of\This in order to use PW for typical web development, then it's a failure. The end goals are in place but not yet the whole plan. The plan should start coming together within the next 1-2 months though. 

Link to comment
Share on other sites

The solution to the deep namespace problems is just a matter of using namespace aliasing.

Code standards are great and a great tool to check on them is PHP_CodeSniffer. In an IDE such as PHPStorm (Ryan I am so sorry) you could just put the formating rules in place and just tell it to reformat the whole thing.

But this is all details compared to converting the source to PSR-0.

Link to comment
Share on other sites

Namespace aliasing is fine, but I'm really hoping to isolate our users from having to think about namespaces at all (unless they want to specifically use something outside of PW). I would gather that most of our users don't care or know about namespaces, so any extra technical verbosity reflects poorly on the simplicity of the system. I don't want people to have to have 'namespace' or 'use' statements at the top of every template file (unless they want to, again), but module files are ok. Not sure if that's even going to be an issue. 

  • Like 1
Link to comment
Share on other sites

  • 6 months later...

Yey, nice time to get involved in ProcessWire. I have been looking at Processwire for a recent project. It is really nice from a user perspective hiding all the complex functionalities. Amazing work guys. I don't say you move to use this or that ( Though I am more inclined towards Aura ;) ).

Composer is really a nice tool, and when we go with composer and you install it is always good to keep the files in vendor folder itself. Some of the things in my mind are

1. Flexibility to move the index.php to outside the main folder. So only index.php is the only file lies there.

else vendor folder will be visible to the public . May be readmes and all .

2. When working on aura v1 , we installed the packages in the package folder itself. But that is a hard way to manage. So we started with http://github.com/auraphp/Aura.Includer/

So it will be nice to have something like adding a certain configuration file in the module of PW which helps to recognise the file is processwires and which needs to be loaded via same ?

Also does the 2.4 development is finished ? There is PSR-4 also coming, which reduces the size of the namespace stuffs.

\ProcessWire\Event\Manager => src/Manager.php ( PSR-4 ) than the previous one /src/ProcessWire/Event/Manager.php

I am looking forward to contribute to PW aslo please choose PSR-2 also. It is all about future and how we all PHP community work ( For I contribute to Aura, Symfony, Zend etc life is easy ) .


  • Like 1
Link to comment
Share on other sites

Composer is really a nice tool, and when we go with composer and you install it is always good to keep the files in vendor folder itself. Some of the things in my mind are

I look forward to getting ProcessWire compatible with Composer. That's one of the things I'd wanted to do with 2.4 though other priorities for ProcessWire have gone ahead of it and likely won't be supporting it till after 2.4, but hopefully soon after. We may need to make changes to directory structure, but I'm averse to doing anything major there as I think we need to give priority to what's best for the web sites that ProcessWire powers over what's best for Composer. But we'll do what we have to do, just always in the context of our intended audience over Composer's (which have crossover, but are also different in many ways). Our audience veers much further towards web developers than dedicated PHP coders. Most of our audience is not integrating multiple PHP projects, but we do want to better support the few that are.

Also does the 2.4 development is finished ? There is PSR-4 also coming, which reduces the size of the namespace stuffs.

2.4 development is pretty much finished. Just trying to work out all the bugs before releasing it. Though I think it is already just as stable as 2.3 for the most part. I am also very interested in evaluating PSR-4 for ProcessWire. With regard to PSR-2, I'm less enthusiastic. Standards are great, and I support the PSR-2 standard for new projects looking to adopt a standard. But I think it's silly for projects that have already adopted a standard, as PSR-2 is a lot of compromise. ProcessWire's own code standard doesn't compromise so much, and in our context PSR-2 is a downgrade. However, I also see it as largely a non-issue. I don't care what standard people contribute code in, as IDEs make it largely irrelevant, at least for the way we merge code here. PhpStorm converts code to ProcessWire's standard automatically. I just encourage people to code in a standard that they find most readable and usable for them, so long as it's consistent. 

  • Like 7
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Similar Content

    • By theExo
      Hey folks,
      im pretty new to Processwire. A client of mine asked me to migrate his old (v2.5) Processwire Website. On his server its running on PHP 5.3 and i want to upgrade + migrate the site at the same time. I Downloaded the Site from his server to set it up locally, replaced the /wire directory, index.php and .htaccess with the files of the latest version. After that i changed the DB Connection details in the config.php, swapped to PHP 7.4 and now, when i open up the site on my localhost i get this error:
      compile(\ProcessWire\wire("config")->paths->root . "site/templates/includes/head.inc.php",array('includes'=>true,'namespace'=>true,'modules'=>true,'skipIfNamespace'=>true)))?> compile(\ProcessWire\wire("config")->paths->root . "site/templates/includes/header.inc.php",array('includes'=>true,'namespace'=>true,'modules'=>true,'skipIfNamespace'=>true)))?> compile(\ProcessWire\wire("config")->paths->root . "site/templates/includes/start_content.inc.php",array('includes'=>true,'namespace'=>true,'modules'=>true,'skipIfNamespace'=>true)))?> compile(\ProcessWire\wire("config")->paths->root . "site/templates/includes/footer.inc.php",array('includes'=>true,'namespace'=>true,'modules'=>true,'skipIfNamespace'=>true)))?> The page itself doesnt load, just a white space with this stuff on it
      I checked if the files exist, they do.
      I hope anyone can help me with that 🙂 Thanks in advance!
    • By MoritzLost
      I've been working with ProcessWire for a while now, and I've noticed that using Composer to manage dependencies and autoload external libraries isn't as prevalent in ProcessWire development as in other areas of PHP programming. I started out by using the default setup recommend in this blogpost. However, one major problem I have with this approach is that all external dependencies live in the webroot (the directory the server points to), which is unfavourable from a security standpoint and, in my opinion, just feels a bit messy.
      In this tutorial, I want to go through a quick setup of Composer and ProcessWire that keeps the dependencies, all custom-written code and other source material outside of the webroot, and makes full usage of the Composer autoloader. This setup is pretty basic, so this tutorial is probably more useful to beginners (this is why I'll also include some general information on Composer), but hopefully everyone can take something away from this for their personal workflow.
      Site structure after setup
      This is what the directory structure can look like after the setup:
      . ├── composer.json ├── composer.lock ├── node_modules │   └── ... ├── public │   ├── index.php │   ├── site │   ├── wire │   └── ... ├── packacke-lock.json ├── package.json ├── sass │   ├── main.scss │   ├── _variables.scss │   └── ... ├── src │   ├── ContentBag.php │   └── ... └── vendor ├── autoload.php ├── composer ├── league ├── symfony └── ... As mentioned, the main point of this setup is to keep all external libraries, all other custom source code and resources out of the webroot. That includes Composer's vendor folder, your node_modules and JavaScript source folder if you are compiling JavaScript with webpack or something similar and including external scripts via NPM, or your CSS preprocessor files if you are using SASS or LESS. In this setup, the public directory acts as the webroot (the directory that is used as the entry point by the server, DocumentRoot in the Apache configuration). So all other files and directories in the mysite folder aren't accessible over the web, even if something goes wrong.
      One caveat of this setup is that it's not possible to install ProcessWire modules through Composer using the PW Module Installer (see Blogpost above), but that's just a minor inconvenience in my experience.
      You'll need to have composer installed on your system for this. Installation guides can be found on getcomposer.org.
      First, open up your shell and navigate to the mysite folder.
      $ cd /path/to/mysite/ Now, we'll initialize a new Composer project:
      $ composer init The CLI will ask some questions about your projects. Some hints if you are unsure how to answer the prompts:
      Package names are in the format <vendor>/<project>, where vendor is your developer handle. I use my Github account, so I'll put moritzlost/mysite (all lowercase). Project type is project if you are creating a website. Author should be in the format Name <email>. Minimum Stability: I prefer stable, this way you only get stable versions of dependencies. License will be proprietary unless you plan on sharing your code under a FOSS license. Answer no to the interactive dependencies prompts. This creates the composer.json file, which will be used to keep track of your dependencies. For now, you only need to run the composer install command to initialize the vendor directory and the autoloader:
      $ composer install Now it's time to download and install ProcessWire into the public directory:
      $ git clone https://github.com/processwire/processwire public If you don't use git, you can also download ProcessWire manually. I like to clean up the directory after that:
      $ cd public $ rm -r .git .gitattributes .gitignore CONTRIBUTING.md LICENSE.TXT README.md Now, setup your development server to point to the /path/to/mysite/public/ directory (mind the public/ at the end!) and install ProcessWire normally.
      Including & using the autoloader
      With ProcessWire installed, we need to include the composer autoloader. If you check ProcessWire's index.php file, you'll see that it tries to include the autoloader if present. However, this assumes the vendor folder is inside the webroot, so it won't work in our case.
      One good place to include the autoloader is using a site hook file. We need the autoloader as early as possible, so we'll use init.php:
      EDIT: As @horst pointed out, it's much better to put this code inside the config.php file instead, as the autoloader will be included much earlier:
      // public/site/config.php <?php namespace Processwire; require '../../vendor/autoload.php'; The following also doesn't apply when including the autoloader in the config-file.
      This has one caveat: Since this file is executed by ProcessWire after all modules had their init methods called, the autoloader will not be available in those. I haven't come across a case where I needed it this early so far; however, if you really need to include the autoloader earlier than that, you could just edit the lines in the index.php file linked above to include the correct autoloader path. In this case, make sure not to overwrite this when you update the core!
      Now we can finally include external libraries and use them in our code without hassle! I'll give you an example. For one project, I needed to parse URLs and check some properties of the path, host et c. I could use parse_url, however that has a couple of downsides (specifically, it doesn't throw exceptions, but just fails silently). Since I didn't want to write a huge error-prone regex myself, I looked for a package that would help me out. I decided to use this URI parser, since it's included in the PHP League directory, which generally stands for high quality.
      First, install the dependency (from the project root, the folder your composer.json file lives in):
      $ composer require league/uri-parser This will download the package into your vendor directory and refresh the autoloader.
      Now you can just use the package in your own code, and composer will autoload the required class files:
      // public/site/templates/basic-page.php <?php namespace Processwire; use \League\Uri\Parser; // ... if ($url = $page->get('url')) { $parser = new Parser(); $parsed_url = $parser->parse($url); // do stuff with $parsed_url ... } Wiring up custom classes and code
      Another topic that I find really useful but often gets overlooked in Composer tutorials is the ability to wire up your own namespace to a folder. So if you want to write some object-oriented code outside of your template files, this gives you an easy way to autoload those using Composer as well. If you look at the tree above, you'll see there's a src/ directory inside the project root, and a ContentBag.php file inside. I want to connect classes in this directory with a custom namespace to be able to have them autoloaded when I use them in my templates.
      To do this, you need to edit your composer.json file:
      { "name": "moritzlost/mysite", "type": "project", "license": "proprietary", "authors": [ { "name": "Moritz L'Hoest", "email": "info@herebedragons.world" } ], "minimum-stability": "stable", "require": {}, "autoload": { "psr-4": { "MoritzLost\\MySite\\": "src/" } } } Most of this stuff was added during initialization, for now take note of the autoload information. The syntax is a bit tricky, since you have to escape the namespace seperator (backslash) with another backslash (see the documentation for more information). Also note the PSR-4 key, since that's the standard I use to namespace my classes.
      The line "MoritzLost\\MySite\\": "src/" tells Composer to look for classes under the namespace \MoritzLost\MySite\ in the src/ directory in my project root. After adding the autoload information, you have to tell composer to refresh the autoloader information:
      $ composer dump-autoload Now I'm ready to use my classes in my templates. So, if I have this file:
      // src/ContentBag.php <?php namespace MoritzLost\MySite; class ContentBag { // class stuff } I can now use the ContentBag class freely in my templates without having to include those files manually:
      // public/site/templates/home.php <?php namespace Processwire; use MoritzLost\MySite\ContentBag; $contentbag = new ContentBag(); // do stuff with contentbag ... Awesome!
      By the way, in PSR-4, sub-namespaces correspond to folders, so I can put the class MoritzLost\MySite\Stuff\SomeStuff in src/Stuff/SomeStuff.php and it will get autoloaded as well. If you have a lot of classes, you can group them this way.
      With this setup, you are following secure practices and have much flexibility over what you want to include in your project. For example, you can just as well initialize a JavaScript project by typing npm init in the project root. You can also start tracking the source code of your project inside your src/ directory independently of the ProcessWire installation. All in all, you have good seperation of concerns between ProcessWire, external dependencies, your templates and your OOP-code, as well as another level of security should your Server or CGI-handler ever go AWOL. You can also build upon this approach. For example, it's good practice to keep credentials for your database outside the webroot. So you could modify the public/site/config.php file to include a config or .env file in your project root and read the database credentials from there.
      Anyway, that's the setup I came up with. I'm sure it's not perfect yet; also this tutorial is probably missing some information or isn't detailed enough in some areas depending on your level of experience. Feel free to ask for clarification, and to point out the things I got wrong. I like to learn as well 🙂
      Thanks for making it all the way to the bottom. Cheers!
    • By MoritzLost
      I've seen a couple of questions regarding namespaces and autoloading floating around the forum recently, so I decided to write a little tutorial. In general, I often see people getting confused when they try to wrap their head around namespaces, autoloading, Composer and the mapping of namespaces to directory structures all at once. In fact, those are very much independent, distinct concepts, and it is much easier to explain and understand them separately. So this guide is structured as follows:
      How namespaces work in PHP. How autoloading works in PHP. Conventions for mapping namespaces to directory structures: PSR-4. How autoloading works in Composer and ProcessWire's class loader. How to use the class loader in a ProcessWire module. Feel free to skip the sections you're already familiar with.
      Namespaces in PHP
      The purpose of namespaces in PHP is to avoid naming conflicts between classes, functions and constants, especially when you're using external libraries and frameworks. Nothing more. It's important to understand that this has nothing at all to do with autoloading, directory structures or file names. You can put namespaced stuff everywhere you want. You can even have multiple namespaces inside a single file (don't try this at home). Namespaces only exist to be able to use a generic name – for example, ProcessWire's Config class – multiple times in different contexts without getting a naming conflict. Without namespaces, I couldn't use any library that includes a Config class of it's own, because that name is already taken. With namespaces, you can have a distinction between the classes ProcessWire\Config and MoritzLost\Config. You can also use sub-namespaces to further segregate your code into logical groups. For example, I can have two classes MoritzLost\Frontend\Config and MoritzLost\Backend\Config– a class name only needs to be unique within it's namespace.
      You can declare the namespace for a PHP file using the namespace statement at the top:
      // file-one.php <?php namespace ProcessWire; // file-two.php <?php namespace MoritzLost\Frontend; This way, all classes, methods and constants defined inside this file are placed in that namespace. All ProcessWire classes live in the ProcessWire namespace.
      Now to use one of those classes – for example, to instantiate it – you have a couple of options. You can either use it's fully qualified class name or import it into the current namespace. Also, if you are inside a namespaced file, any reference to a class is relative to that namespace. Unless it starts with a backward slash, in this case it's relative to the global namespace. So all of those examples are equivalent:
      // example-one.php <?php namespace ProcessWire; $page = new Page(); // example-two.php <?php use ProcessWire\Page; $page = new Page(); // example-three.php <?php $page = new ProcessWire\Page(); // example-four.php <?php namespace MoritzLost\Somewhere\Over\The\Rainbow; $page = new \ProcessWire\Page(); The use statement in the second example can be read like this: “Inside this file, all references to Page refer to the class \ProcessWire\Page”
      How autoloading works
      Every PHP program starts with one entry file – for ProcessWire, that's usually it's index.php. But you don't want to keep all your code in one file, that would get out of hand quickly. Once you start to split your code into several individual files however, you have to take care of manually including them with require or include calls. That becomes very tedious as well. The purpose of autoloading is to be able to add new code in new files without having to import them manually. This, again, has nothing to do with namespaces, not even something with file locations. Autoloading is a pretty simple concept: If you try to use a class that hasn't been loaded yet, PHP calls upon it's registered autoloaders as a last-ditch attempt to load them before throwing an exception.
      Let's look at a simple example:
      // classes.php <?php class A { /** class stuff */ } class B { /** class stuff */ } // index.php <?php spl_autoload_register(function ($class) { include_once 'classes.php'; }); new A(); new B(); This is a complete and functional autoloader. If you don't believe me, go ahead and save those two files (classes.php and index.php) and run the index.php with php -f index.php. Then comment out the include_once call and run it again, then you'll get an error that class A was not found.
      Now here's what happens when index.php is executed (with the autoloader active):
      Our anonymous function is added to the autoload queue through spl_autoload_register. PHP tries to instantiate class A, but can't because it's not loaded yet. If there was no autoloader registered, the program would die with a fatal error at this point. But since there is an autoloader ... The autoloader is called. Our autoloader includes classes.php with the class definition. That was a close one! Since the class has been loaded, execution goes back to the index.php which can now proceed to instantiate A and B. If the class was still not loaded at this point, PHP would go back to the original plan and die. One thing to note is that the autoloader will only be called once in this example. That's because both A and B are in the same file and that file is included during the first call to the autoloader. Autoloading works on files, not on classes!
      The important takeaway is that PHP doesn't know if the autoloader knows where to find the class it asks for or, if there are multiple autoloader, which one can load it. PHP just calls each registered autoloader in turn and checks if the class has been loaded after each one. If the class still isn't loaded after the last autoloader is done, it's error time.
      What the autoloader actually does is pretty much wild wild west as well. It takes the name of the class PHP is trying to load as an argument, but it doesn't have to do anything with it. Our autoloader ignores it entirely. Instead, it just includes classes.php and says to itself “My job here is done”. If class A was in another file, it wouldn't have worked.
      This process has two main advantages:
      Since autoloaders are only called on-demand to load classes just in time, we only include the files we actually need. If in the example above class A and B are not used in some scenarios, the classes.php will not be included, which will result in better performance for larger projects (though this isn't as cut and dry, since autoloading has it's own overhead, so if you load most classes anyway during a single request, it will actually be less efficient). If the autoloader is smart enough to somehow map class names to the files they're located in, we can just let the autoloader handle including the classes we need, without having to worry about jamming include statements everywhere. That brings us to ... PSR-4, namespaces and directory structures
      As you see, namespaces and autoloading are both pretty limited concepts. And they aren't inherently linked to each other. You can namespace your classes without ever adding an autoloader, and you can autoload classes that are all in the same namespace. But they become useful when you put them together. At the core of all that autoloading talk is a simple idea: By putting classes in files named after their class names, and putting those files in directory hierarchies based on the namespace hierarchy, the autoloader can efficiently find and load those files based on the namespace. All it needs is a list of root namespaces with their corresponding directories.
      The exact way class names and namespaces are mapped to directory structures and file names is purely conventional. The accepted convention for this is PSR-4. This is a super simple standard which basically just sums up the ideas above:
      A base namespace is mapped to a specific directory in the file system. When the autoloader is asked to load a class in that namespace (or a sub-namespace of it), it starts looking in that folder. This "base" namespace may include multiple parts – for example, I could use MoritzLost\MyAwesomeLibrary as a base and map that to my source directory. PSR-4 calls this a "namespace prefix". Each sub-namespace corresponds to a sub-directory. So by looking at the namespace, you can follow subdirectories to the location where you expect to find the class file. Finally, the class name is mapped directly to the file name. So MyCoolClass needs to be put inside MyCoolClass.php. This all sounds simple and straightforward - and it absolutely is! It's only once you mash everything together, mix up language features, accepted conventions and proprietary implementations like Composer on top that it becomes hard to grasp in one go.
      Composer and ProcessWire's class loader
      Now all that's left is to talk about how Composer and ProcessWire provide autoloading.
      Composer, of course, is primarily a tool for dependency management. But because most libraries use namespaces and most developers want to have the libraries they're using autoloaded, those topics become a prerequisite to understanding what Composer does in this regard. Composer can use different autoloading mechanisms; for example, you can just give it a static list of files to include for every request, or use the older PSR-0 standard. But most modern libraries use PSR-4 to autoload classes. So all Composer needs to function is a mapping of namespace prefixes to directories. Each library maintains this mapping for it's PSR-4-structured classes through the autoload information in their composer.json. You can do this for your own site to: Just include the autoload information as shown in the documentation and point it to the directory of your class files.
      Composer collects all that information and uses it to generate a custom file at vendor/autoload.php — that's the one you need to include somewhere whenever you set up Composer in one of your projects. Bells and whistles aside, this file just registers an autoloader function that will use all the information collected from your own and your included libraries' composer.json to locate and include class files on demand.
      You can read more about how to optimize Composer's autoloader for production usage here. If you want to read up on how to set up Composer for your own sites, read my ProcessWire + Composer integration guide instead.
      And finally, what does ProcessWire do to handle all this? Turns out, ProcessWire has it's own autoloader implementation that is more or less PSR-4 compliant. You can access it as an API variable ($classLoader or wire('classLoader'), depending on context). Instead of using a static configuration file like Composer, the namespace -> directory mapping is added during the runtime by calling $classLoader->addNamespace. As you would expect, this function accepts a namespace and a directory path. You can use this to register your own custom namespaces. Alternatively, if you have site-specific classes within the ProcessWire namespace, you can just add their location to the class loader using the same method: $classLoader->addNamespace('ProcessWire', '/path/to/your/classes/').
      Utilizing custom namespaces and autoloading in ProcessWire modules
      Now as a final remark, I wanted to give an example of how to use custom namespaces and the class loader in your own modules. I'll use my TrelloWire module as an example:
      Decide what namespace you're going to use. The main module file should live in the ProcessWire namespace, but if you have other classes in your module, they can and should use a custom namespace to avoid collisions with other modules. TrelloWire uses ProcessWire\TrelloWire, but you can also use something outside the ProcessWire namespace. You need to make sure to add the namespace to the class loader as early as possible. If either you or a user of your module tries to instantiate one of your custom classes before that, it will fail. Good places to start are the constructor of your main module file, or their init or ready methods. Here's a complete example. The module uses only one custom namespaced class: ProcessWire\TrelloWire\TrelloWireApi, located in the src/ directory of the module. But with this setup, I can add more classes whenever I need without having to modify anything else.
      /** * The constructor registers the TrelloWire namespace used by this module. */ public function __construct() { $namespace = 'ProcessWire\\TrelloWire'; $classLoader = $this->wire('classLoader'); if (!$classLoader->hasNamespace($namespace)) { $srcPath = $this->wire('config')->paths->get($this) . 'src/'; $classLoader->addNamespace($namespace, $srcPath); } } Source
      Thanks for making it through to the very end! I gotta learn to keep those things short. Anyway, I hope this clears up some questions about namespaces and autoloading. Let me know if I got something wrong, and feel free to add your own tips and tricks!
    • By MrSnoozles
      Hey everyone,
      I was just wondering what is the purpose of autoloading the file wire/core/ProcessWire.php in composer.json? As far as I can see that file gets required again anyway in index.php, around line 32.

      For me this line has no purpose but one major drawback: When requiring ProcessWire as dependecy in a module (e.g. to write tests against a clean ProcessWire installation), an error is thrown that the class is already in use.
      Fatal error: Cannot declare class ProcessWire\ProcessWire, because the name is already in use
      Does this autoloading have any purpose?
    • By chrizz
      I am currently developing a little application which is supposed to run on a raspberry. I decided to take advantage of PW's capabilities to deal with data not only in the sense of a common website but more as an application. 
      I wrote a lot of modules for this and I wrote tests for some of the methods (using PHPUnit). This works fine so far for methods which are independent from database (e.g. calculating an upcoming date/time by a given schedule). Now I am thinking of extending this by writing tests also for methods which rely on data from the database (e.g. it need to be checked if something exists on that given date/time). This information is currently stored as page in PW. 
      One of my thoughts: create necessary pages in PW for running the test and delete them afterwards. But somehow this just feels wrong. 
      Any kind of input how you would tackle this would be great!
      Thanks a lot! 
  • Create New...