Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: xp-forge/htmx
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.3.0
Choose a base ref
...
head repository: xp-forge/htmx
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Mar 29, 2024

  1. Use PHP 7.4 badge [skip ci]

    thekid committed Mar 29, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    85ffbe4 View commit details

Commits on Jan 11, 2025

  1. Use SVG badge

    thekid committed Jan 11, 2025
    Copy the full SHA
    594c05e View commit details

Commits on Feb 3, 2025

  1. Delegate URL handling, namespacing and user information

    thekid committed Feb 3, 2025
    Copy the full SHA
    af97a10 View commit details
Showing with 96 additions and 20 deletions.
  1. +6 −0 ChangeLog.md
  2. +2 −2 README.md
  3. +43 −1 src/main/php/web/frontend/HtmxFlow.class.php
  4. +45 −17 src/test/php/web/frontend/unittest/HtmxFlowTest.class.php
6 changes: 6 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,12 @@ HTMX for XP web frontends change log

## ?.?.? / ????-??-??

## 1.0.0 / 2025-02-03

* Delegated URL handling, namespacing and user information to underyling
flow instances.
(@thekid)

## 0.3.0 / 2024-03-29

* Dropped support for PHP 7.0 - 7.3, step 1 of xp-framework/rfc#343
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@ HTMX for XP web frontends
[![Build status on GitHub](https://github.com/xp-forge/htmx/workflows/Tests/badge.svg)](https://github.com/xp-forge/htmx/actions)
[![XP Framework Module](https://raw.githubusercontent.com/xp-framework/web/master/static/xp-framework-badge.png)](https://github.com/xp-framework/core)
[![BSD Licence](https://raw.githubusercontent.com/xp-framework/web/master/static/licence-bsd.png)](https://github.com/xp-framework/core/blob/master/LICENCE.md)
[![Requires PHP 7.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_0plus.svg)](http://php.net/)
[![Requires PHP 7.4+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_4plus.svg)](http://php.net/)
[![Supports PHP 8.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-8_0plus.svg)](http://php.net/)
[![Latest Stable Version](https://poser.pugx.org/xp-forge/htmx/version.png)](https://packagist.org/packages/xp-forge/htmx)
[![Latest Stable Version](https://poser.pugx.org/xp-forge/htmx/version.svg)](https://packagist.org/packages/xp-forge/htmx)

HTMX Integration

44 changes: 43 additions & 1 deletion src/main/php/web/frontend/HtmxFlow.class.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php namespace web\frontend;

use web\auth\Flow;
use web\auth\{Flow, URL, UserInfo};

/**
* Wraps around any authentication flow and ensures that if there is the
@@ -16,6 +16,48 @@ class HtmxFlow extends Flow {
/** Creates a new instance, wrapping around a given flow */
public function __construct(Flow $delegate) { $this->delegate= $delegate; }

/**
* Sets session namespace for this flow. Used to prevent conflicts
* in session state with multiple OAuth flows in place.
*
* @param string $namespace
* @return self
*/
public function namespaced($namespace) {
$this->delegate->namespaced($namespace);
return $this;
}

/**
* Targets a given URL
*
* @param web.auth.URL $url
* @return self
*/
public function target(URL $url) {
$this->delegate->target($url);
return $this;
}

/**
* Returns URL
*
* @param bool $default
* @return ?web.auth.URL
*/
public function url($default= false): URL {
return $this->delegate->url($default);
}

/**
* Returns a user info instance
*
* @return web.auth.UserInfo
*/
public function userInfo(): UserInfo {
return $this->delegate->userInfo();
}

/**
* Refreshes access token given a refresh token if necessary.
*
62 changes: 45 additions & 17 deletions src/test/php/web/frontend/unittest/HtmxFlowTest.class.php
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@

use lang\IllegalStateException;
use test\{Assert, Test};
use web\auth\{Authorization, Flow};
use web\auth\{Authorization, Flow, UseRequest, UseURL, UserInfo};
use web\frontend\HtmxFlow;
use web\io\{TestInput, TestOutput};
use web\{Request, Response};
@@ -16,35 +16,63 @@ private function authenticate(array $headers, Flow $flow): Response {
return $res;
}

/** Returns a flow delegate */
private function delegate(?callable $auth): Flow {
return newinstance(Flow::class, [], [
'userInfo' => function(): UserInfo { return new UserInfo('strtoupper'); },
'namespace' => function() { return $this->namespace; },
'authenticate' => $auth ?? function($request, $response, $session) { /* NOOP */ },
]);
}

#[Test]
public function can_create() {
new HtmxFlow(new class() extends Flow {
public function authenticate($request, $response, $session) {
// NOOP
}
});
new HtmxFlow($this->delegate(null));
}

#[Test]
public function returns_delegates_user_information() {
Assert::equals('TEST', (new HtmxFlow($this->delegate(null)))->userInfo()('test'));
}

#[Test]
public function returns_delegates_default_url() {
Assert::instance(UseRequest::class, (new HtmxFlow($this->delegate(null)))->url(true));
}

#[Test]
public function delegates_namespacing() {
$delegate= $this->delegate(null);
(new HtmxFlow($delegate))->namespaced('test');

Assert::equals('test', $delegate->namespace());
}

#[Test]
public function delegates_target_url() {
$delegate= $this->delegate(null);
$url= new UseURL('https://example.com');
(new HtmxFlow($delegate))->target($url);

Assert::equals($url, $delegate->url());
}

#[Test]
public function delegates_authentication() {
$res= $this->authenticate([], new HtmxFlow(new class() extends Flow {
public function authenticate($request, $response, $session) {
$response->answer(302);
$response->header('Location', '/login');
}
}));
$res= $this->authenticate([], new HtmxFlow($this->delegate(function($request, $response, $session) {
$response->answer(302);
$response->header('Location', '/login');
})));

Assert::equals(302, $res->status());
Assert::equals('/login', $res->headers()['Location']);
}

#[Test]
public function returns_error_code_and_triggers_authenticationexpired_event() {
$res= $this->authenticate(['HX-Request' => 'true'], new HtmxFlow(new class() extends Flow {
public function authenticate($request, $response, $session) {
throw new IllegalStateException('Never called');
}
}));
$res= $this->authenticate(['HX-Request' => 'true'], new HtmxFlow($this->delegate(function($request, $response, $session) {
throw new IllegalStateException('Never called');
})));

Assert::equals(401, $res->status());
Assert::equals('authenticationexpired', $res->headers()['HX-Trigger']);