Skip to content

[Filesystem] Add the Path class #30969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 21 commits into from

Conversation

theofidry
Copy link
Contributor

@theofidry theofidry commented Apr 7, 2019

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? no
Fixed tickets #26523
License MIT
Doc PR -

The current Filesystem component is great to deal with the actual file system. It is however lacking when it comes to manipulating with file paths, and when it does, it checks the paths existence which might not what you desire in certain cases.

This PR proposes to merge webmozart/path-util (the path related part only) to Symfony. The library has been very stable, well tested, well documented, but is lacking some love as webmozart doesn't have time to check it anymore.

The current state is the original as is to get a first assessment on what to be changed before working more on this if there is an interest.

It is also worth mentioning that this class has been heavily used in Box and Puli with success among others.

Copy link
Contributor

@webmozart webmozart left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still wrong file headers and wrong @since comments. Otherwise I love it, but I'm obviously biased. 😄

@nicolas-grekas nicolas-grekas changed the title [WIP] Add the Path class [Filesystem] Add the Path class Apr 7, 2019
Copy link
Contributor

@OskarStark OskarStark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of making this a standalone component? Or is It to much overhead? Maybe this abstraction could be quite helpful for the php eco system without requiring the whole filesystem component.

@nicolas-grekas nicolas-grekas added this to the next milestone Apr 7, 2019
@kunicmarko20
Copy link

Any reason why this is modelled as a util class instead of a value object, wouldn't that be more useful?

@webmozart
Copy link
Contributor

Any reason why this is modelled as a util class instead of a value object, wouldn't that be more useful?

This class is a very low level building block designed to support thousands of calls to its methods. The only notable state is the home directory, which is only relevant if you use ~ in your paths.

Under these aspects, I don't see the point of complicating this to:

$path = new Path();
$relativePath = $path->makeRelative('/foo/bar', '/foo');

The methods are pure (except if you use ~, which you shouldn't in tests), hence testability is not an issue.

@kunicmarko20
Copy link

I was thinking more like:

$path = new Path('/foo/bar');
$path->canonicalize();

I guess the issue is that I have no idea where this class is gonna be used as this PR just adds it and doesn't actually show where it is going to be used.

@theofidry
Copy link
Contributor Author

@kunicmarko20 I would instantiate Path. It's mostly stateless functions and when it's not it's for performance reasons (and having it in a class avoids to have to use the global state as an alternative).

It's also not something you really want to abstract/mock, so there is really no reason to have to instantiate it.

I guess the issue is that I have no idea where this class is gonna be used as this PR just adds it and doesn't actually show where it is going to be used.

I don't know if there is a lot of cases within the Symfony codebase to be honest. I however pointed two projects using it a lot.

@apfelbox
Copy link
Contributor

If we make it a value object, practically all of these functions should return a new Path and not a string, and the object should implement __toString().

Might be quite convenient to have it as a VO, but it will work as static methods as well (that's how node.js does it).

@theofidry
Copy link
Contributor Author

If we make it a value object, practically all of these functions should return a new Path and not a string, and the object should implement __toString().

@apfelbox that would be quite an overhead; It's fine if you approach paths as a VO in your codebase and performances are not an issue, but in projects like Box or Puli in which it's being used, it's unreasonable.

@theofidry
Copy link
Contributor Author

theofidry commented Apr 11, 2019

What do you think of making this a standalone component? Or is It to much overhead?

@OskarStark This would be quite an overhead IMO, also the FS component is relatively light so I don't think it's an issue.

@apfelbox
Copy link
Contributor

@theofidry ok, in this case I would stick to static methods. 👍

@theofidry
Copy link
Contributor Author

theofidry commented Apr 11, 2019

Fabbot fixed, the Travis & AppVeyor failures seem unrelated

@theofidry
Copy link
Contributor Author

status: needs review

@theofidry theofidry force-pushed the feature/path-component branch from a7cb394 to 2688745 Compare September 26, 2019 19:24
@theofidry
Copy link
Contributor Author

Rebased against master. The Travis failure looks unrelated (it's about the Cache component)

@OskarStark
Copy link
Contributor

OskarStark commented Sep 26, 2019

Would be happy to get this merged 🥰🥳

BTW, Shouldnt this go into 4.4 as a new feature?

@theofidry
Copy link
Contributor Author

theofidry commented Dec 10, 2019

Can a decision be taken about this class?

Just to put things in context: this class can be seen as complementary to the Filesystem as the last has a lot of similar path-related methods, the main difference being that the Filesystem will check their existences. Path is more meant as a path manipulator without doing any existence check whatsoever which is very useful to manipulate/construct/change paths without side-effects.

The main question IMO is whether or not this class is a good fit for the current Filesystem component, which brings the question of the main purpose of the Filesystem component. To put things in perspective, the Filesystem component is 8 years old (originally created by willdurand) and has been (regardless of the original intent) ever since then a thin layer on top of some file system related PHP native functions to patch/enrich them.

// Windows root
if (\strlen($path) > 1 && ctype_alpha($path[0]) && ':' === $path[1]) {
// Special case: "C:"
if (2 === \strlen($path)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See php/php-src#5001 , C: is oficially not an absolute path.

@chalasr
Copy link
Member

chalasr commented Dec 11, 2019

Can a decision be taken about this class?

It looks useful to me. And I think Filesystem is a good fit for it.
Making core uses it internally may help moving forward, I suggest looking at places where this could be used.

@fabpot
Copy link
Member

fabpot commented Oct 7, 2020

We've just moved away from master as the main branch to use 5.x instead. Unfortunately, I cannot reopen the PR and change the target branch to 5.x. Can you open a new PR referencing this one to not loose the discussion? Thank you for your understanding and for your help.

@tomasfejfar
Copy link
Contributor

@theofidry do you plan to reopen the PR? :)

chalasr added a commit that referenced this pull request Aug 13, 2021
This PR was merged into the 5.4 branch.

Discussion
----------

[Filesystem] Add the Path class

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | Fix #26523
| License       | MIT
| Doc PR        | TODO

Re-opening #30969 as requested by \`@fabpot`.

This PR proposes a low-level, performant and pure API to manipulate file paths.

Two methods `Path::isAbsolute()` and `Path::isRelative()` are similar to `Filesystem::isAbsolutePath()` and `Filesystem::makePathRelative()`. They are however different as the methods from `Path` do not check the existence of the path which is very helpful in some scenarios (for example when manipulating virtual paths such as "regular" paths of a PHAR).

The original code comes from [webmozart/path-util](https://github.com/webmozart/path-util) from which the path part was extracted. The library is very stable, well tested and documented. It has been heavily used in [Puli](https://github.com/puli), which although is no longer active has been a good performance test and is used in several other popular projects such as:

- vimeo/psalm
- drush/drush
- infection/infection
- humbug/box
- humbug/php-scoper
- phpbench/phpbench

It however suffers from lack of maintener from `@webmozart` which no longer has time to maintain it.

Commits
-------

512b476 Add the Path class
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.