Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion assets/vue/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ const redirectToLogin = () => {

const appElement = document.getElementById('vue-app');
const apiToken = appElement?.dataset.apiToken;
const apiBaseUrl = appElement?.dataset.apiBaseUrl;
const apiElement = document.getElementById('api-config');
const apiBaseUrl = apiElement?.dataset.apiBaseUrl;

if (!apiBaseUrl) {
console.error('API Base URL is not configured.');
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
},
"require": {
"php": "^8.1",
"phplist/core": "dev-main",
"phplist/core": "dev-env",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

composer validate --strict
composer show phplist/core --all | grep -F 'dev-env'
rg -n 'createDotenvConfiguration' composer.lock vendor 2>/dev/null || true

Repository: phpList/web-frontend

Length of output: 1350


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== composer.json =="
cat -n composer.json | sed -n '1,130p'

echo
echo "== composer.lock phplist entries =="
sed -n '1,220p' composer.lock | rg -n -C 3 '"phplist|source:|version":' || true
}

echo
echo "== createDotenvConfiguration definitions/usages =="
rg -n 'createDotenvConfiguration|ComposerHandler|ScriptHandler|update-configuration' composer.json vendor composer.lock 2>/dev/null || true

Repository: phpList/web-frontend

Length of output: 5519


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import json
from pathlib import Path

lock = Path("composer.lock")
print("composer.lock exists:", lock.exists())
if lock.exists():
    data = json.loads(lock.read_text())
    packages = {p.get("name"): p for p in data.get("packages", []) + data.get("packages-dev", [])}
    for name in ["phplist/core", "phplist/api-client"]:
        if name in packages:
            p = packages[name]
            print(name, "version=", p.get("version"), "source=", {k:p["source"].get(k) for k in ("type","url","reference")})
        else:
            print(name, "NOT IN lock")
else:
    print("No composer.lock present")
PY

Repository: phpList/web-frontend

Length of output: 211


🌐 Web query:

phpList core dev-env createDotenvConfiguration PhpList\Core\Composer\ScriptHandler

💡 Result:

The reference to PhpList\Core\Composer\ScriptHandler::createDotenvConfiguration appears to be related to internal Composer script handling, likely used during the installation or setup process of a phpList application. Based on current technical documentation and development resources for phpList: 1. Installation and Setup: The primary method for setting up a phpList development environment is using Docker, which is the officially supported approach [1][2]. For a local setup, documentation typically directs users to configure environment files (such as.env or parameter files like config/parameters.yml) manually or via provided examples [3][4][1][5]. 2. Composer Script Handlers: While ScriptHandler classes are common in PHP applications (often based on Symfony) to automate tasks like generating environment configuration files (e.g., from a.env.dist file), there is no prominent public documentation explicitly detailing a method named createDotenvConfiguration within the PhpList\Core namespace. It is highly probable that this method is an internal, non-public helper function used during the composer install process to ensure necessary configuration files exist. 3. Development Workflow: If you are setting up a development environment, you should follow the official phpList Docker development guide [4][2] or the standard local setup instructions [1]. These guides emphasize using provided example configuration files to establish your local environment rather than relying on manual invocation of internal script handlers [4][1]. If you are encountering errors related to this script handler during a composer operation, ensure your composer.json is correctly configured and that you are working within a supported phpList base distribution [3][5].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp -d)"
cd "$tmp"

echo "== fetch phpList/core refs =="
git ls-remote --heads https://github.com/phplist/core.git | grep -E '(refs/heads/|^refs/tags/).*' | sed -n '1,80p'

echo
echo "== fetch phpList/core branch metadata =="
remote="$(git ls-remote --symref https://github.com/phplist/core.git refs/heads/dev-env | sed -n '1p')"
echo "$remote"

echo
echo "== inspect repo branch if present =="
if git ls-remote https://github.com/phplist/core.git refs/heads/dev-env | grep -q 'refs/heads/dev-env'; then
  git clone --quiet --depth 1 --branch dev-env --single-branch https://github.com/phplist/core.git "$tmp/core-dev-env"
  echo "== composer handlers in core/dev-env =="
  rg -n 'createDotenvConfiguration|class ScriptHandler|ScriptHandler' "$tmp/core-dev-env"
else
  echo "dev-env branch not present"
fi

Repository: phpList/web-frontend

Length of output: 469


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmp="$(mktemp -d)"
cd "$tmp"

for branch in env main; do
  echo "== inspect branch $branch =="
  git clone --quiet --depth 1 --branch "$branch" --single-branch https://github.com/phplist/core.git "$tmp/core-$branch"
  echo "== relevant handler entries in core/$branch =="
  rg -n --hidden -C 3 'createDotenvConfiguration|class ScriptHandler|function create|ScriptHandler' "$tmp/core-$branch/composer.phplist-core.php" "$tmp/core-$branch" 2>/dev/null | sed -n '1,220p'
done

Repository: phpList/web-frontend

Length of output: 23028


Use the existing phplist/core branch name.

phplist/core:dev-env points to a branch that doesn’t exist in phpList/core; Composer needs a valid branch, e.g. phplist/core:dev-env if that branch is created, or another existing branch such as env.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@composer.json` at line 54, Update the phplist/core dependency version in
composer.json to reference an existing branch in phpList/core, replacing the
invalid dev-env constraint with the correct available branch name such as env.

"symfony/twig-bundle": "^6.4",
"symfony/webpack-encore-bundle": "^2.2",
"symfony/security-bundle": "^6.4",
Expand Down Expand Up @@ -96,6 +96,7 @@
"PhpList\\Core\\Composer\\ScriptHandler::createBundleConfiguration",
"PhpList\\Core\\Composer\\ScriptHandler::createRoutesConfiguration",
"PhpList\\Core\\Composer\\ScriptHandler::createParametersConfiguration",
"PhpList\\Core\\Composer\\ScriptHandler::createDotenvConfiguration",
"PhpList\\Core\\Composer\\ScriptHandler::clearAllCaches"
],
"publish-phplist-texts": [
Expand Down
2 changes: 2 additions & 0 deletions config/packages/twig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ twig:
strict_variables: '%kernel.debug%'
default_path: '%kernel.application_dir%/templates'
auto_reload: true
globals:
api_base_url: '%app.api_base_url%'
6 changes: 1 addition & 5 deletions config/services.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# config/services.yaml
parameters:
api_base_url: '%env(API_BASE_URL)%'
env(API_BASE_URL): 'http://api.phplist.local/'

services:
_defaults:
autowire: true
Expand All @@ -27,7 +23,7 @@ services:
Symfony\Component\HttpFoundation\Session\SessionInterface: '@session'

PhpList\RestApiClient\Client:
$baseUrl: '%api_base_url%'
$baseUrl: '%app.api_base_url%'

PhpList\WebFrontend\EventListener\ApiSessionListener:
tags:
Expand Down
4 changes: 2 additions & 2 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/6.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
bootstrap="tests/bootstrap.php"
>
<php>
<env name="API_BASE_URL" value="http://api.phplist.local/"/>
<ini name="error_reporting" value="-1"/>
<server name="KERNEL_CLASS" value="PhpList\Core\Core\ApplicationKernel"/>
<server name="APP_ENV" value="test" force="true"/>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</php>
</phpunit>
2 changes: 0 additions & 2 deletions src/Controller/AnalyticsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public function index(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Analytics',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
2 changes: 0 additions & 2 deletions src/Controller/BouncesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ public function index(Request $request): Response

return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Bounces',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
'bounce_actions' => $bounceActions,
]);
}
Expand Down
6 changes: 0 additions & 6 deletions src/Controller/CampaignsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public function index(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Campaigns',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -27,8 +25,6 @@ public function create(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Create Campaign',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -37,8 +33,6 @@ public function edit(Request $request, int $campaignId): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => sprintf('Edit Campaign #%d', $campaignId),
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
2 changes: 0 additions & 2 deletions src/Controller/DashboardController.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ public function index(Request $request): Response

return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Dashboard',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
'dashboard_stats' => $dashboardStats,
'dashboard_error' => $dashboardError,
]);
Expand Down
4 changes: 0 additions & 4 deletions src/Controller/ListsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ public function index(Request $request): JsonResponse|Response
if (! $wantsJson) {
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Lists',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
$initialData = $this->listClient->getLists();
Expand All @@ -40,8 +38,6 @@ public function view(Request $request, int $listId): JsonResponse|Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'List Subscribers',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
6 changes: 0 additions & 6 deletions src/Controller/PublicPagesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public function index(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Subscribe Pages',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -27,8 +25,6 @@ public function create(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Create Subscribe Page',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -37,8 +33,6 @@ public function edit(Request $request, int $pageId): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => sprintf('Edit Subscribe Page #%d', $pageId),
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
2 changes: 0 additions & 2 deletions src/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public function index(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Settings',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
2 changes: 0 additions & 2 deletions src/Controller/SubscribersController.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ public function index(Request $request): JsonResponse|Response
if (! $wantsJson) {
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Subscribers',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand Down
6 changes: 0 additions & 6 deletions src/Controller/TemplatesController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ public function index(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Templates',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -27,8 +25,6 @@ public function create(Request $request): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => 'Create Template',
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}

Expand All @@ -37,8 +33,6 @@ public function edit(Request $request, int $templateId): Response
{
return $this->render('@PhpListFrontend/spa.html.twig', [
'page' => sprintf('Edit Template #%d', $templateId),
'api_token' => $request->getSession()->get('auth_token'),
'api_base_url' => $this->getParameter('api_base_url'),
]);
}
}
1 change: 1 addition & 0 deletions templates/base.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<meta charset="UTF-8">
<title>{% block title %}phpList{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta id="api-config" data-api-base-url="{{ api_base_url }}">
<link rel="stylesheet" href="{{ asset('build/app.css', 'phplist_web_frontend') }}">
<link rel="stylesheet" href="{{ asset('build/styles.css', 'phplist_web_frontend') }}">

Expand Down
3 changes: 1 addition & 2 deletions templates/spa.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@

{% block body %}
<div id="vue-app"
data-api-token="{{ api_token|default('') }}"
data-api-base-url="{{ api_base_url|default('') }}"
data-api-token="{{ app.session.get('auth_token')|default('') }}"
data-dashboard-stats="{{ dashboard_stats|default({})|json_encode|e('html_attr') }}"
data-dashboard-error="{{ dashboard_error|default('')|e('html_attr') }}"
data-bounce-actions="{{ bounce_actions|default({})|json_encode|e('html_attr') }}">
Expand Down
4 changes: 3 additions & 1 deletion tests/Integration/Controller/AnalyticsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpList\WebFrontend\Controller\AnalyticsController;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RouterInterface;
Expand All @@ -27,12 +28,13 @@ public function testAnalyticsPageRendersExpectedSpaPayload(): void
self::bootKernel();
/** @var AnalyticsController $controller */
$controller = static::getContainer()->get(AnalyticsController::class);
$apiBaseUrl = (string) static::getContainer()->getParameter('api_base_url');
$apiBaseUrl = (string) static::getContainer()->getParameter('app.api_base_url');

$request = Request::create('/analytics/');
$session = new Session(new MockArraySessionStorage());
$session->set('auth_token', 'integration-token');
$request->setSession($session);
static::getContainer()->get(RequestStack::class)->push($request);

$response = $controller->index($request);
$content = (string) $response->getContent();
Expand Down
4 changes: 3 additions & 1 deletion tests/Integration/Controller/BouncesControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpList\WebFrontend\Controller\BouncesController;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RouterInterface;
Expand All @@ -27,12 +28,13 @@ public function testBouncesPageRendersExpectedSpaPayload(): void
self::bootKernel();
/** @var BouncesController $controller */
$controller = static::getContainer()->get(BouncesController::class);
$apiBaseUrl = (string) static::getContainer()->getParameter('api_base_url');
$apiBaseUrl = (string) static::getContainer()->getParameter('app.api_base_url');

$request = Request::create('/bounces/');
$session = new Session(new MockArraySessionStorage());
$session->set('auth_token', 'integration-token');
$request->setSession($session);
static::getContainer()->get(RequestStack::class)->push($request);

$response = $controller->index($request);
$content = (string) $response->getContent();
Expand Down
2 changes: 2 additions & 0 deletions tests/Integration/Controller/CampaignsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PhpList\WebFrontend\Controller\CampaignsController;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RouterInterface;
Expand Down Expand Up @@ -41,6 +42,7 @@ public function testCampaignPagesRenderExpectedSpaPayload(
$session = new Session(new MockArraySessionStorage());
$session->set('auth_token', 'integration-token');
$request->setSession($session);
static::getContainer()->get(RequestStack::class)->push($request);

$response = $controller->{$action}($request, ...$actionArguments);

Expand Down
4 changes: 3 additions & 1 deletion tests/Integration/Controller/DashboardControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use PhpList\WebFrontend\Controller\DashboardController;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RouterInterface;
Expand All @@ -29,7 +30,7 @@ public function testDashboardRouteIsRegistered(): void
public function testDashboardRendersSpaPayloadWithStats(): void
{
self::bootKernel();
$apiBaseUrl = (string) static::getContainer()->getParameter('api_base_url');
$apiBaseUrl = (string) static::getContainer()->getParameter('app.api_base_url');

$statsClient = $this->createMock(StatisticsClient::class);
$statsClient->expects(self::once())
Expand All @@ -43,6 +44,7 @@ public function testDashboardRendersSpaPayloadWithStats(): void
$session = new Session(new MockArraySessionStorage());
$session->set('auth_token', 'integration-token');
$request->setSession($session);
static::getContainer()->get(RequestStack::class)->push($request);

$response = $controller->index($request);
$content = (string) $response->getContent();
Expand Down
4 changes: 3 additions & 1 deletion tests/Integration/Controller/ListsControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Routing\RouterInterface;
Expand All @@ -31,7 +32,7 @@ public function testListRoutesAreRegistered(string $routeName, array $parameters
public function testListsIndexRendersSpaForHtmlRequests(): void
{
self::bootKernel();
$apiBaseUrl = (string) static::getContainer()->getParameter('api_base_url');
$apiBaseUrl = (string) static::getContainer()->getParameter('app.api_base_url');

$listClient = $this->createMock(ListClient::class);
$listClient->expects(self::never())->method('getLists');
Expand Down Expand Up @@ -106,6 +107,7 @@ private function createRequestWithSession(string $path): Request
$session = new Session(new MockArraySessionStorage());
$session->set('auth_token', 'integration-token');
$request->setSession($session);
static::getContainer()->get(RequestStack::class)->push($request);

return $request;
}
Expand Down
11 changes: 11 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

use Symfony\Component\Dotenv\Dotenv;

require dirname(__DIR__) . '/vendor/autoload.php';

if (method_exists(Dotenv::class, 'bootEnv')) {
(new Dotenv())->bootEnv(dirname(__DIR__) . '/.env');
}
Loading