URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

URL Class - #4647

Closed
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls
Closed

URL Class#4647
MGatner wants to merge 4 commits into
codeigniter4:developfrom
MGatner:urls

Conversation

@MGatner

Copy link
Copy Markdown
Member

Description
"Stage Three", this PR introduces a companion class to URI: URL. The URL class handles internal URIs (i.e. specific to the project) in the following manner:

  • A URL is always constructed with a relative path
  • A URL will always use the App config values from its construction (baseURL, indexPage, forceGlobalSecureRequest)
  • A URL is immutable, not affected by changes to $_SERVER or services once it has been created

I would like URL to become the definitive source for internal URLs within the framework (e.g. replace the logic in base_url() and current_url(), be used by RedirectResponse, etc) but for now this PR is just introducing the concept and demonstrating the tests. Please be thorough with any reviews, since URLs have been a long pain point (particularly around subfolders).

Note: This PR relies on #4644 and #4646.

Checklist:

  • Securely signed commits
  • Component(s) with PHPdocs
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@lonnieezell

Copy link
Copy Markdown
Member

Haven't looked at the code yet but my initial thought is - this is making the framework more complex and confusing than it needs to be. Can we just start prepping for a bigger release and fix this in the existing URI class? Have two classes so closely related to each other are going to be super confusing for any devs that dig into the inner workings. Or just to those who's IDE starts to suggest both classes for them.

Additionally - isn't the purpose of site_url to be base_url but taking index.php settings into account?

@MGatner

Copy link
Copy Markdown
MemberAuthor

We really need both. It doesn't need to be implemented this way, but we need to be able to do two things:

  1. Build out a URI representing any valid URI for use anywhere one would want a URI
  2. Build "project-specific" URIs, based off the configuration in App and (potentially) any special routes

Currently this is a real problem:

// If hosted in a sub-folder, we will have additional
// segments that show up prior to the URI path we just
// grabbed from the request, so add it on if necessary.
$config = config(App::class);
$baseUri = newself($config->baseURL);
$basePath = trim($baseUri->getPath(), '/') . '/';
$path = $this->getPath();
$trimPath = ltrim($path, '/');
if ($basePath !== '/' && strpos($trimPath, $basePath) !== 0)
{
$path = $basePath . $trimPath;
}
// force https if needed
if ($config->forceGlobalSecureRequests)
{
$this->setScheme('https');
}

I've tried to mitigate it in #4646 but this "bleeds" point 2 into point 1. URI should not know or care about the framework settings because it makes it impossible to create any URI one might want because the framework settings take over.

Currently we handle "project-specific" URIs with the URL Helper functions (base_url(), site_url(), current_url()) - the problem with these is that the final project has no concept of "what is project" versus "what is path" (e.g. http://example.com/foo/bar - is the baseURLhttp://example.com/ with "foo/bar" path? or is it http://example.com/foo/ with "bar" path?) so I decided to go with a class solution so we have some way of storing and accessing that info.

I originally had URL as FrameworkURI that was an extension of URI, but there are too many setters in URI that could "violate" an internal URI so I split it out; at that point I realized it was basically a full URL so went with the name, but I'm open to changing it.

@MGatner

Copy link
Copy Markdown
MemberAuthor

isn't the purpose of site_url to be base_url but taking index.php settings into account

Exactly. site_url() amounts to "take base_url(), add App::$indexPage, add any given path, be smart about slashes." URL::to() tries to encompass this behavior but with a little more utility of resolving named and reverse routes.

Comment threadsystem/HTTP/URL.php
*/
public static function base()
{
return static::public('');

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since the class is final, then inheritance is no more possible. So, there's no need to use the static keyword. Instead use self.

Suggested change
returnstatic::public('');
returnself::public('');

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

On the topic, how do you think the class should be scoped? Originally I had a normal class with final static and constructor methods (hence the leftover static references here) but I decided that nobody would go through the hassle of extending for the few allowed methods so made the whole thing final.

Comment threadsystem/HTTP/URL.php
$config = clone config('App');
$config->indexPage = '';

return new static($uri, $config);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic($uri, $config);
returnnewself($uri, $config);

Comment threadsystem/HTTP/URL.php
Comment on lines +70 to +71
$config = clone config('App');
$config->indexPage = '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
$config = cloneconfig('App');
$config->indexPage = '';
$config = cloneconfig('App');
$config->indexPage = '';

Comment threadsystem/HTTP/URL.php
return self::$current;
}

return static::fromRequest(Services::request());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnstatic::fromRequest(Services::request());
returnself::fromRequest(Services::request());

Comment threadsystem/HTTP/URL.php
*/
public static function to(string $uri)
{
return new static(rtrim($uri, '/ '));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
returnnewstatic(rtrim($uri, '/ '));
returnnewself(rtrim($uri, '/ '));

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Additional URI string to include
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
/**
* Returns an instance representing the current URL.
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param string $uri Named or reverse route
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

Comment threadsystem/HTTP/URL.php
*
* @param IncomingRequest $request
*
* @return static

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* @return static
* @return self

@lonnieezell

Copy link
Copy Markdown
Member

I'll be honest. I'm not a fan of having both. I understand your reasoning but think it will make things more complex/confusing for the developers. I wish we could find a way to refactor the current class to work in conjunction with the url helpers.

That being said, if the rest of the team is fine with it then I'll shut up :)

@MGatner

Copy link
Copy Markdown
MemberAuthor

@lonnieezell I understand. Let's think of ways we could make this better. I do think the helpers could be "beefed" up to cover this class but we would lose the ability to distinguish path parts (see my comment about "what is project" versus "what is path"). That might be an acceptable tradeoff? But there are some real issues with the current setup that need addressing. Just an example, IncomingRequest is clear that it only builds out the URI it needs for itself:

// Determine the current URI
// NOTE: This WILL NOT match the actual URL in the browser since for
// everything this cares about (and the router, etc) is the portion
// AFTER the script name. So, if hosted in a sub-folder this will
// appear different than actual URL. If you need that, use current_url().
$this->uri = $uri;
$this->detectURI($config->uriProtocol, $config->baseURL);

If you need that, use current_url().

... but then this is the entirety of current_url():

$uri = clone Services::request()->uri;

I believe that a support class (in this case URL) gives us a lot more flexibility than the helper functions for working with framework URIs - maybe we could make it an internal class? or move it out of HTTP?

@MGatnerMGatner mentioned this pull request May 6, 2021
5 tasks
@MGatnerMGatner closed this May 11, 2021
@MGatnerMGatner mentioned this pull request Feb 16, 2023
5 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@MGatner@lonnieezell@paulbalandan