Problem/Motivation
After #1975220: Allow a Composer user to manage Drupal, modules, and PHP dependencies with a custom root composer.json it is finally possible to manage a Drupal 8 site properly with Composer. One important aspect of that is controlling the autoloader Drupal uses. So instead of core/vendor/autoload.php (or wherever/i/choose/to/put/my/docroot/core/vendor/autoload.php) being used the one Composer generated for the entire project should be used, i.e. vendor/autoload.php (or wherever/i/choose/to/put/my/docroot/vendor/autoload.php). This works well for index.php by simply altering the $autoloader = require_once __DIR__ . '/core/vendor/autoload.php'; line appropriately. (When using a subtree split of Drupal, that is not hacking core.) It also works for install.php after #2386247: install.php should pass the class loader down into install_begin_request(), but since that is inside of the core directory that is hacking core.
The same goes for authorize.php, rebuild.php, run-tests.sh, &hellips;.
In general Drupal currently does not allow to control the autoloader of front controllers and that is a problem.
Proposed resolution
Add a authorize.php in the root of the repository which simply includes the autoloader in core/vendor/autoload.php. By placing it into the root of the repository we make it legitimately editable by people using Composer to manage their sites, so that they can simply alter the default autoload.php to include the autoloader they want. It is also a huge benefit that this is now consolidated into a single file and not multiple files need to be updated (Single-Responsibility-Principle, Don't-Repeat-Yourself, yada, yada...).
Remaining tasks
User interface changes
None.
API changes
None.
Beta phase evaluation
| Issue category | Bug because for people using Composer install.php does not work under certain circumstances. |
|---|---|
| Issue priority | |
| Prioritized changes | Prioritized because this is a bug fix and could not go in after a stable release. |
| Disruption | Not disruptive. Changing things like index.php only disrupts The Composer People© (and even them ever so slightly) but they are precisely the ones championing this change |
| Comment | File | Size | Author |
|---|---|---|---|
| #76 | 2406681-2.76.patch | 5.04 KB | hussainweb |
| #53 | 2406681-2.53.patch | 5.03 KB | alexpott |
| #53 | 50-53-interdiff.txt | 1.09 KB | alexpott |
| #50 | 2406681-50.patch | 4.35 KB | tstoeckler |
Comments
Comment #1
tadityar commentedMoved.
Comment #2
tstoecklerYeah, I don't think it's such a quick fix... :-)
I searched for all references of 'authorize.php', 'rebuild.php', and 'install.php' in core and found a bunch of stuff that needs updating. I also tested all three files and they work fine. Well 'authorize.php' didn't work internally, but AFAIK that's a pre-existing issue (even though I can't find the issue right now) and at least it showed up and showed errors etc. correctly.
Comment #4
tstoecklerOh sorry, I am an idiot. I forgot
-C -M. Naming -do-not-test, because it's literally the same thing, so no need to make the bot test this twice. This is the one that should be reviewed, though.Comment #5
tadityar commentedahaha I thought moving would be sufficient so I added the Quick fix tag :)
Comment #6
tstoecklerNo problem :-)
Thanks to you, we have proof that additional changes are necessary and we also know that we don't need to add any test coverage.
Comment #7
dawehnerThis allows people to use a
composer.jsoneven more than intended. On top of that it removes a couple of hacks we have currently in Drupal.Sadly authorize.php itself is quite big, but I fear that we can remove it anyway, as nobody cares about the install module functionality.
Comment #8
tstoecklerRe-uploading the -C -M patch to make sure it's green as well.
Comment #9
catchStatistics.
Shouldn't we move most of authorize.php to a new file in /core and include it from the front controller, we already have an issue to put most of index.php back into /core.
Yay.
Comment #10
tstoecklerRe 1.: In fixing that I realized that that hunk in my previous patch was completely bogus. The regular expression explicitly disallows the "/" character, so the rule only matches files in /core directly, not in subfolders. But with the patch we don't have any of those anymore. statistics.php actually has a dedicated RewriteCond, a few lines below that. So removed that whole part.
Re 2.: It feels really icky to add a new file in
includesat this point, I think I need to take a shower now. But however much I would like to deny it, it is an improvement over the status quo so I went for it. Instead ofauthorize_send_response()I would have liked to have aauthorize_render_page()that returns a response object, which is then "send()ed" fromauthorize.php. This would have required more refactoring than I'm comfortable with in this issue, though, because the response is only conditionally sent. I also tested that authorize.php still "works" just as well as it does in 8.0.x. Note that the patch actually moves core/authorize.php to core/includes/authorize.inc and copies core/authorize.php to authorize.php (i.e. Git++, but it looks kind of weird).Comment #11
dawehnerGreat work!
Comment #13
hussainwebRerolled against changes from #2364157: Replace most existing _url calls with Url objects.
Comment #14
tstoecklerRe - roll looks good, thanks!
Comment #16
dawehner.
Comment #17
almaudoh commentedRe-rolled
Comment #18
hussainwebI was going to reset RTBC as per #14 but I see the file sizes differ somewhat. Was it a straight reroll?
Comment #19
almaudoh commented@hussainweb it is the same patch (I verified), just that #17uses renames for
core/install.php -> install.phpandcore/rebuild.php -> rebuild.phpinstead of explicit "deleted file mode" and "new file mode"Comment #20
tstoecklerVerified, that the reroll is correct. Thanks!
Comment #21
alexpottI think we need a new 8.0.x to 8.0.x change record here and a search to find the original CR for moving them so we can unpublish that one.
Comment #22
hussainwebHere is the old change record: https://www.drupal.org/node/1327978
Here is a draft change record: https://www.drupal.org/node/2420145
I have not unpublished the old change record. I am guessing we should do that on RTBC or when it gets committed, correct?
Comment #23
hussainwebCome to think of it, I don't think we can unpublish the old change record as it contains information for other files as well which still holds true. I guess we just have to edit that change record to add these files to the list of the files that remain in the old location.
Comment #24
ParisLiakos commentedyes. i updated existing change notice
Comment #26
ParisLiakos commentedreroll
Comment #28
hussainwebI just checked the patch in #26 and see that a file was missing. I just rerolled from #17 again to keep things simple.
Comment #29
hussainwebRTBC as per #24.
Comment #31
hussainwebFixing the failure.
Comment #32
tstoecklerAwesome, thanks!
Comment #33
alexpottI don't think this will work for statistics.php and run-tests.sh
I have an idea.
Comment #34
alexpottTotally new approach so no interdiff.
Comment #36
alexpottComment #37
jibranI think we should add a rule in .htaccess that user can't access this directly.
Comment #38
alexpott@jibran good point.
Comment #39
alexpott@tstoeckler, @almaudoh, @ParisLiakos - what are you thoughts on the recent patches - shall I update the issue summary to reflect the change of direction?
Comment #40
hussainwebI was thinking about this approach earlier, but it was in a different context. My main concern then was that there is a new file to be loaded in the request pipeline. I guess it does not make a lot of difference.
I think it might make some sense to have a separate autoloader (which we can readily use in another file, such as drushrc.php). But still, I wish we could do away with authorize.php, update.php, etc... in core directory.
Comment #41
ParisLiakos commentedYes, i agree with #40.
It would be nice to move those files to the root to get rid of hacks (that only work for Apache anyway), but the approach solves the problem here, so from my side its RTBC.
Would like to leave it to tstoeckler though.
Comment #42
almaudoh commented@alexpott: I have to say the new approach is simpler, but like the others I have to ask: would there be some other situation in future where we would want to change install.php, authorize.php, etc? These are front controllers in their own right.
The patch solves the current issue though. Let's hear from @tstoeckler.
Comment #43
alexpottI totally not against the moving the front controllers. But it does not solve the composer issue - see run-tests.sh and statistics.php (or any other contrib module that wanted to do something similar).
Comment #44
tstoecklerYes, this is a great idea, thanks!
I will move my patch to a separate follow-up issue.
Added a small comment to the .htaccess change and marking RTBC as I didn't write any code for the latest patch (but for the little comment).
Also updated issue title and summary.
*canihazwebinstallwithcomposersetupplz* :-)
Comment #45
tstoeckler....and, I'm an idiot. Here is mentioned patch.
Comment #46
tstoecklerOpened #2427093: Move front controllers (install.php, rebuild.php) to repository root.
Comment #47
jibranDo we need to update web.config for the same rule?
Comment #48
alexpottre #47 afaics we don't have any equivalent rule in web.config.
Comment #50
tstoecklerRerolled.
The previous patch weirdly contained #2426979: Remove obsolete PNG images from Shortcut module.
Comment #51
alexpottBack to rtbc then
Comment #52
webchickHm, I need a little bit of help understanding this. This patch basically makes the path:
autoload.php -> core/vendor/autoload.php -> core/vendor/composer/autoload_real.phpThat's a lot of layers of indirection, and not something I've seen done in any other project.
And from the issue summary:
Why is hacking a core file "legitimately editable"? I guess because people using your Composer workflow are only downloading the /core part of Drupal, not the / part of Drupal that contains index.php etc?
Basically, I think the header of the authorize.php file needs to either contain or point to some specific docs explaining all of this a bit more. As it stands, from an "outside" point of view, it's pretty confusing.
What's the rationale for this change? If we're disallowing all .php files, that should include autoload.php, no?
Comment #53
alexpott.htaccess is editable per project and included in our repo - I would argue that editing anything outside /core is not hacking core. In fact this issue once upon a time moved all of the front controllers into the root directory so you could edit them.
So what makes Drupal a special flower.
Joomla split their repo to do this and created Joomla framework see http://magazine.joomla.org/issues/issue-aug-2013/item/1450-getting-start...
We never did the necessary work wrt to how we package Drupal or organise the repositories.
Do you mean autoload.php? I guess you do.
That rule only blocks access to .php files in a subdirectory of the root folder. Autoload.php is, by design, in the root folder.
Comment #54
mile23Hmm. We need a composer meta. I just duplicated this here: #2380389: Use a single vendor directory in the root
The main difference being that we should check for the existence of
DRUPAL_ROOT/vendor/autoload.phpbefore includingcore/vendor/autoload.php. That way autoloading works immediately after you've saidcomposer install, without modifyingautoload.php.The main thing standing in the way of a reasonable Composer implementation is the attitude that changing
composer.jsonis 'hacking core.' It isn't. It's managing your project. If we were to overcome that, we wouldn't have discussions of whetherautoload.phpwere legitimate for the root directory, because we would instead just do the normal thing and let composer put the autoload.php file where it should be and then not care at all. :-)Because we are working around this expectation, we end up with an autoloading front controller and the possibility of having the user manage two vendor directories when they say
composer install.I'm giving a Composer talk at SANDcamp this coming weekend. Also will be at MidCamp if anyone wants a BoF or other discussion about Composer. And I guess I need to submit the talk again for DrupalCamp LA because no one seems to get how odd it is that we have this constraint on a modern PHP project.
Comment #55
mile23Comment #56
mile23#2432893: Make Compser DrupalWTF Go Away
Comment #57
alexpottPutting a
file_existsin index.php or the new autoload.php added by this patch is not a great idea - that will an unnecessary file operation to every request.Comment #58
tstoecklerChanges look good to me.
Marking RTBC again and assigning to @webchick to see whether that adresses the concerns.
Comment #59
mile23I understand the concern of a file operation, but we're already loading
root/autoload.phpand then subsequentlyroot/core/vendor/autoload.php. Which then loads a bunch of files itself, because it is *also* a façade for some autogenerated class loading code. So we're up to a minimum of three file loads already without checking if a file exists. Furthermore, file_exists() caches its result, so we only do it once.And again: The big concern seems to be that people will 'hack core' so let's just make one less file for them to need to 'hack' in order to make the top-level
composer.jsonwork.Or, of course, just ditch this hobo contraption and just use composer like a normal PHP project. :-)
Comment #60
davidwbarratt commentedI'm ok with it either way. It's nice if it works out of the box, but most people are not going to use composer in the first place and it seems silly to enforce a
file_exists()on a file that is not going to exist for 95%* of users.Then again, we perform a file operation every time module_load_include() is run (or whatever the D8 equivalent is).
As for me, I'll be modifying
autoload.phpanyways, because I prefer for mycomposer.jsonand myvendor/to be outside the webroot completely.I also think most enterprise users are not going to mind modifying a single file, because as you've already stated, you're not "hacking core" if you modify
.htaccessorcomposer.json(or anything outside ofcore/for that matter).Also, your snide comment that Drupal is not like every other project, simply is not true:
https://www.drupal.org/node/2432893#comment-9654365
but let's leave that discussion for the other thread.
* I admit that I have no idea how many people will use Composer, but I feel it will be a minority.
Comment #61
davidwbarratt commentedMost enterprise clients are going to modify that file for performance reasons anyways (i.e. to remove the
file_exists).Comment #62
davidwbarratt commentedThe only thing I'm concerned about, is that technically now we have somewhat of a circular dependency,
drupal/drupalrequiresdrupal/coreand thendrupal/corerequires at least anautoload.phpfile.However, I admit that that does not mean you must use
drupal/drupalyou could use any package, but the package would have to implement anautoload.phpin../core(whereever that is).I think that's an acceptable loss to get us to the point where we're only loading from a single autoload file. In an ideal world, all of the "entry points" would be in
drupal/drupal(which would remove the circular dependency). This is what they've done in Symfony and Symfony Standard. All of the entry points are in the latter, which means the autoload path can be changed on a project level and the former does not give a rip as long as it's loaded.Since I can't see that happening in the 8.x cycle, I think what we have is as good as it's going to get.
Comment #63
mile23That is a worthwhile goal. In Symfonyland we have
web/which is where the front controller lives, and no one mistakes the root forweb/. How did it happen in Symfonyland? A technical need was understood to exist, and then engineers decided it was a good idea to address this technical need with a technical solution.But because we live in Drupalland, where things are a certain way for cultural and political reasons rather than technical ones, we have issues like this one, where we have to argue whether to do file_exists() in a file that acts as a facade for another facade file in order to meet our cultural needs about 'hacking core.' Not 'hacking core' is a cultural need that arose from a technical one, but is now causing us to introduce DrupalWTF all over the place, because it is a cultural need at odds with a technical solution.
As far as how many will use composer to install Drupal 8 in it's current state: NONE, because it doesn't work, and when it eventually does, the instructions will say: "Use the root composer.json file in order to manage your own dependencies. But also change the autoload.php file so it points to the autoload.php file that is managed by composer. We know this is different from the way you're used to using composer, but trust us, it's better because you're not 'hacking core.'"
You will find, in the future, that if we *can* have a painless Drupal installation through composer, that will become the preferred way of installing it, more ubiquitous than git or even the tarball.
Comment #64
davidwbarratt commentedI hear what you are saying, as I've said, I don't think modifying
index.phpis hacking core at all since it's on the "project level" (i.e. not in the core directory).However, that's not the only entry point to Drupal, and unless we are willing to move all of the entry points into the project level, I think this is the next best solution.
And I for one will always install Drupal with composer, because it is painless. You can do something like:
and with that Drupal is ready to go. If I want to add custom dependencies (only a developer is going to do that anyways), I know from the Drupal documentation (and the readme in
composer.json) that there is an extra step I need to do. I think that's perfectly acceptable given where we are in the 8.0 cycle. It's not ideal, I agree 100%, but unless we're willing to move all the entry points, and the vendor directory, that's where we are at.Comment #65
alexpott@Mile23
The technical reason why don't have a /web directory is because we target shared hosting as a platform to run Drupal on. @Mile23, I find what you've written to be insulting to other core developers. Also, somewhat ironically, by what you've written you've made a technical issue with a technical solution, political by comparing Drupalland to Symfonyland.
btw the point about the file_exists() is also technical and not political - we try to minimise all disk access before page cache is checked. Adding a file exists here is most certainly before the page is cached. Also technically this one would not be cached, quoting the PHP manual:
Comment #66
catchLoading a file via require/include is completely different from file_exists() on a non-existing file. This has been pointed out many times before, such as #340723-108: Make modules and installation profiles only require .info.yml files. Stracing apache is a straightforward way to see what the difference is.
"Normal PHP projects" don't have constraints such as being able to install from scratch by unpacking a tarball on some hosting then visiting install.php (with few or zero additional steps depending on the hosting). Integrating composer (and vendor libraries) needs to be done with an understanding of the existing feature set that Drupal has and its use-cases. Sometimes that means re-examining the use-cases/features, sometimes it means changing things upstream (like PSR-4 and Composer support for it), sometimes it means compromises or Drupal-specific adaptations.
Also on "Don't hack core" - that's a dogma, but like many technical dogmas it evolved from sound technical concerns. In my day job we still end up auditing client sites with undocumented hacks to core and/or contrib modules which are completely unnecessary, and I'm always thankful when I go to upgrade a module and can see at a glance which upstream patches are applied to it.
Generally we expect large sites to swap out things like cache backends, but we don't expect them to manually undo bad performance choices made by core. Also this assumes that a medium-sized site running on a VPS (or cloud hosting with a slow file system) isn't going to have a problem with disk access on every request (including internal page cache hits).
Comment #67
webchickThanks for the docs and the explanation on the autoload.php rule in .htaccess (oops, duh). My concerns are addressed with the patch itself, but not sure I'm the most qualified to commit it, so I'd rather defer to catch on this (sounds like he's +1).
Mile23, you're definitely not winning any friends nor arguments here with your attitude, so I'd recommend recalculating a different strategy.
Comment #68
mile23This isn't a tantrum over
file_exists().I'm saying that there's a bigger problem with Drupal's Composer stuff. And also kindasorta with the Drupal dev process.
I'm not trying to be insulting. It's just frustrating.
The current patch creates a need to hack core by design, something I was told is very important not to do by @webchick in IRC. This is why I went along with the dual composer.json thing to begin with. It's the best workaround for an absolute technical need to not hack core. It's also why I didn't start on other modifications and decided to instead focus on the grunt work of stuff like this: #1800046: [META] Add missing type hinting to core docblocks, fix Drupal.Commenting.FunctionComment.Missing*
However, now we find ourselves in the position of asking users to intentionally hack core for some use cases, in order to support the brittle solution that is a workaround for the principle of not hacking core. Do you see the irony?
This is different from suggesting the user modify .htaccess or the example gitignore, because Drupal won't be able to autoload its classes unless you hack core in these cases.
If users are now allowed to do whatever they want in DRUPAL_ROOT, then life gets a lot easier for people who want to design a system to let contrib specify dependencies through Composer. It also means that our workaround 'working example' composer.json system is kind of silly.
So can I go ahead and work on things that 'hack core' now, or not? If not hacking core is an absolute technical need, then no, I can't. If not hacking core is really a gray area, then why was I told it wasn't?
(Answer: It's not really a technical need, as proved by #66 on and the RTBC. And that's what I'm talking about when I say 'cultural or political need...' Just that the need is mitigated by other factors which no one will tell you, but you are nevertheless expected to know.)
So can someone with the authority to do so please write down the conditions under which a user is allowed to hack core, so that Drupal devs can then refer to this specification when trying to understand how to solve a complex problem? Thanks.
Comment #69
davidwbarratt commentedThe goal (at least for me) in #1975220: Allow a Composer user to manage Drupal, modules, and PHP dependencies with a custom root composer.json was to move Drupal's code into
/core, which then frees upcomposer.jsonto be modified by the user.I think in
/corenothing should be modified (I'm not even going to keep that folder in my repo's since composer will load it for me anyways). Anything outside of that folder, well, is more of a grey area. I wouldn't willy-nilly hack anything outside of/core, but I don't think there's a strict rule against it. Anything that should never be modified by the user should really be incore/.The same thing is true for any other library. Composer even recommends leaving the vendor directory out of your repo.
https://getcomposer.org/doc/faqs/should-i-commit-the-dependencies-in-my-...
Because of this, if you modify anything in
vendor/you're hacking that library. I look at Drupal core the same way.As far as the "working example sillyness" you speak of, as I've said before, if you execute this command:
it works, right now without modifying anything at all. If you were to delete the
<root>/composer.jsonit would stop working. After you run this command, you're free to modify the<root>/composer.jsonhowever you'd like, you'll also need to follow the instructions in the file and modifyautoload.php.I also see now that not having
file_existsis the way to go, so I approve this change. :)Comment #70
mile23That was in answer to @davidwbarrat's reference to a comment he left in another thread. See #60 where he refers to this comment: https://www.drupal.org/node/2432893#comment-9654365
Symfony was completely refactored in version 2 for something like the use cases we are discussing here (among others, of course). It's fair to say that David's comparison isn't completely wrong, but it's not at all right in the context he's making it, because the two communities' development attitudes are not at all the same.
Here's a non-rhetorical question: What engineering principles are we using to refactor Drupal for the use case of someone who wants to specify a vendor directory outside of core?
It's non-rhetorical because we have a patch. The patch adds an autoload.php file which acts as front controller for another front controller for code autogenerated by Composer. It also leaves core/vendor intact which may or may not be an issue... The reasons for supporting this use case are unclear on whether this matters.
So we have someone (David) who wants to move their vendor directory to a non-standard location. We have no idea why. We have a patch that violates some rule about hacking core, for some reason that is deemed justified by maintainers. We have a solution that leaves vendor/ in place within core for some reason that might be related to the rule about hacking core, but which also might be a problem for David. This patch is RTBCd by the person who asked for it who is not a maintainer.
Where's the engineering?
What is the basis for supporting this use case by asking people to hack core?
The Symfony solution was to separate everything into decoupled packages. Ours is to... what? Decide it's OK to tell users to hack core.
I'm not saying we shouldn't do it, I'm saying that if David wants to bring up that other comparison I'll talk about it, and I'm also here to correct you: It is not a political comparison. It is a realistic comparison of differing development processes. The unfortunate part is that if I talk about it, there is political fallout within the Drupal community *for me.*
Comment #71
mile23We are in agreement.
Historically, there has been a strict rule against just that, communicated to me by a maintainer in regard to Drupal's Composer stuff. Apparently it's not a strict rule any more, as of now. For some reason.
I'm totally OK with that. It's something I want.
+1 on the 'needs change record' so we can reflect to the rest of the world that DRUPAL_ROOT is now userland.
Comment #72
davidwbarratt commentedI just want to point out that Symfony 2.0 was released on July 28, 2011
http://symfony.com/blog/symfony-2-0
The initial release of Composer wasn't until March 1st 2012
https://github.com/composer/composer/blob/master/CHANGELOG.md#100-alpha1...
It's a little nonsensical to think that Symfony was refactored to use Composer. I actually remember some crazy depency management system that had
.depsfiles etc. That's all been destroyed (in the 2.x lifecycle) and they've embraced Composer. I don't think that happened overnight at all. I don't think PSR-0 happened overnight either.My point is only that we don't have to refactor all of Drupal to use Composer. We can certainly make it better (like moving the /vendor directory up a level or moving it out of the repository, etc.), but that doesn't have to happen today. We can take this in increments and I think that's perfectly acceptable.
Comment #73
davidwbarratt commentedI also want to point out that there is an effort to decouple components from core:
https://github.com/drupal/drupal/blob/8.0.x/core/lib/Drupal/Component/RE...
Each of the components (https://github.com/drupal/drupal/tree/8.0.x/core/lib/Drupal/Component) are going to need read-only subtree splits (I haven't created the issue yet), much in the same way Symfony has them (https://github.com/symfony).
I only point this out to say we're on the right track, and it's not an overnight job by any means.
Comment #74
mile23See also: https://www.drupal.org/node/1818628#comment-9672571
Comment #76
hussainwebRerolling to keep this issue alive.
Comment #77
tstoecklerThanks!
Comment #79
catchWe added the /core directory so that modifying files below that level doesn't end up being 'hacking core' - the idea being that by removing all meaningful code from those files they won't change during the entire 8.x cycle (short of an absolute emergency we couldn't anticipate) so there'll never be conflicts to resolve.
This patch is consistent with that (as well as enabling better composer setups) so committed/pushed to 8.0.x, thanks!
Comment #80
davidwbarratt commentedcatch,
Should the change record be published?
Comment #81
tstoecklerYes, and it seems that has been done by now. Thanks all, this was a biggie!
Comment #82
mile23The change record about requiring users to change files in DRUPAL_ROOT to enable normal functioning? I don't see that one.
Comment #83
davidwbarratt commented#82,
It's been in the docs for a while, I'll update it later to reflect this change.
https://www.drupal.org/node/2404989
Comment #84
mile23That's not a change notice.
Comment #85
davidwbarratt commentedUpdated to reflect the changes.
https://www.drupal.org/node/2404989
if you'd like a change notice, you're more than welcome to write one. :)
Comment #87
davidwbarratt commentedThis issue has caused a regression #2464055: Installation Failure on case insensitive file systems