Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Core Laravel Package

phplist/core

Core library for phpList, the open-source newsletter and email marketing system. Provides shared domain logic, models, and services for managing subscribers, lists, campaigns, and message sending in PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

phpList 4 Core is not a standalone app — it is a Symfony bundle plus a domain layer (entities, repositories, services, migrations) for the phpList 4 mailing-list platform. You consume it from a Symfony application (the official phplist/base-distribution is one), not by cloning it and running it.

Minimal steps:

  1. composer require phplist/core in an existing Symfony 4.x/5.x app (PHP 7.x). The current tagged release is v4.0.0-alpha5; no detailed release notes were published for it, so treat it as a pre-stable alpha. If dependency resolution fails against modern Symfony, pin "phplist/core": "4.0.0-alpha5" or "dev-master" against a compatible Symfony version.
  2. Register the bundle in config/bundles.php:
    PhpList\Core\Bundle\CoreBundle::class => ['all' => true],
    
  3. Configure a Doctrine DBAL/ORM connection in config/packages/doctrine.yaml — Core relies on the default connection and its own mappings/migrations.
  4. Import the bundle's service and routing config (the bundle ships Resources/config/services.yml and Doctrine mapping in its Resources/config/doctrine directory; autoloading is handled by the bundle extension).
  5. Create/update the schema with the Core console commands (namespace phpList:):
    bin/console phpList:database:create
    bin/console phpList:database:update
    
  6. Verify wiring with bin/console debug:container 'PhpList\Core' and bin/console doctrine:mapping:info.

Where to look first:

  • src/Bundle/CoreBundle.php — the integration seam; everything else is reachable from here.
  • src/Domain/Model/ — entities such as Subscription\Subscriber, Subscription\SubscriberList, Messaging\Campaign, Administration\Administrator. This is the API you will actually use day-to-day.
  • src/Domain/Repository/ — Doctrine repositories with query helpers.
  • src/Infrastructure/ — persistence, migrations, and technical services.
  • src/Application/ — console commands and DI definitions.

First use case: create a subscriber and attach it to a list programmatically.

use PhpList\Core\Domain\Model\Subscription\Subscriber;
use PhpList\Core\Domain\Model\Subscription\SubscriberList;

class OnboardingService
{
    public function __construct(
        private EntityManagerInterface $em,
        private SubscriberRepository $subscribers,
    ) {}

    public function subscribe(string $email, string $listName): void
    {
        $subscriber = new Subscriber();
        $subscriber->setEmail($email);
        $subscriber->setConfirmed(true);
        $this->em->persist($subscriber);

        $list = $this->em->getRepository(SubscriberList::class)
            ->findOneBy(['name' => $listName]);

        $subscription = new Subscription($subscriber, $list);
        $this->em->persist($subscription);
        $this->em->flush();
    }
}

Once that works, the second natural step is driving campaigns: create a Campaign, attach it to a list, queue messages, and let the phpList process-manager commands (phpList:processqueue, phpList:sendqueue) do the sending.

Implementation Patterns

Depend on repositories and services, not the EntityManager, from your app code. Core exposes PhpList\Core\Domain\Repository\* services via the bundle's DI config. Autowire them into your controllers, commands, and Messenger handlers. This keeps your code insulated from Core's schema when it changes.

public function __construct(
    private SubscriberRepository $subscribers,
    private SubscriptionRepository $subscriptions,
) {}

Treat Core entities as your domain model and extend the bundle, not the class, for customization. Entity classes are Doctrine-mapped by the bundle; subclassing them means replicating mapping metadata and is fragile. Prefer:

  • A custom Symfony service that wraps Core repositories for business logic.
  • Symfony event listeners/subscribers on Core's dispatched events to hook into lifecycle transitions (subscription confirmation, bounce processing, campaign send).
  • Custom console commands for operational tasks, calling Core services directly.

Use the official distribution + Core for anything user-facing. The phplist/base-distribution repo wires Core into a runnable Symfony app with web UI, and phplist/rest-api exposes Core resources over HTTP. For headless integrations, install the REST API package and call it rather than reimplementing HTTP routes against Core.

Batch through console commands. The phpList model assumes queue processing runs out-of-band. Schedule phpList:processqueue / phpList:sendqueue (or your own wrapper commands) via cron or a supervisor. Do not send mail synchronously from a web request.

Migrations are the schema contract. In CI and local dev, always run phpList:database:update after pulling; Core's migrations live in the bundle and are the single source of truth. In your app, create your own migrations directory and keep it separate from Core's so upgrades do not conflict.

Testing pattern. Spin up a dedicated phpList_test database, load schema via phpList:database:update --env=test, and wrap each test in a transaction or use dama/doctrine-test-bundle. Core has its own PHPUnit suite — mirror its fixtures when you need realistic subscriber/list data.

Integration seam for other systems. Use the repositories for read paths (e.g., export subscribers by list) and write via services that enforce invariants (blacklist checks, confirmation state) rather than raw SQL. If you must write SQL, mirror the constraints in Core's migration files.

Pin and test against the alpha explicitly. v4.0.0-alpha5 is pre-1.0-quality in the SemVer sense: internal APIs and schema may still shift between alpha tags. Pin the exact version in composer.json, commit composer.lock, and re-run your test suite after any bump. Do not rely on ^4.0 ranges resolving to a compatible alpha.

Gotchas and Tips

  • AGPL-3.0 is a real product risk, not a formality. If you run a modified phpList as a network service, the AGPL requires you to offer source to users of that service. Budget for legal review if you build a hosted/SaaS product on Core.
  • Still alpha, still low-activity. v4.0.0-alpha5 is the current release, but it is a pre-stable alpha with no detailed changelog published — do not assume it fixes the compatibility issues that have dogged earlier tags. The repo (~89 stars) remains a niche project; expect friction with contemporary Symfony/PHP versions. Pin your Symfony version and your Core version exactly, and if you need dev-master, commit to tracking the branch and running its test suite after upgrades.
  • Not runnable by itself. composer require phplist/core gives you a bundle, not a working app. There is no bin/console until you create a Symfony kernel or pull in base-distribution. Newcomers lose hours here — check the distribution repo first if you just want phpList running.
  • Migrations and schema must be run explicitly. Core does not auto-create tables on first request. Forgetting phpList:database:update produces confusing "table not found" errors deep in repository code.
  • Service IDs are namespaced. Look them up with bin/console debug:container | grep PhpList rather than guessing PhpList\Core\Domain\Repository\SubscriberRepository — the bundle may alias interfaces to concrete classes. Autowiring by type is the safe path.
  • Doctrine mapping lives inside the bundle. Do not copy mapping files into your app; you will desynchronize from Core's migrations. If you need extra fields, add them in your own entity + migration that references Core's table, and be aware of upgrade risk.
  • Two mail paths, one process manager. Core separates queue population (campaign → message rows) from queue sending (processqueue). If mail "isn't going out," check the process manager/cron first — then check campaign status and list membership — before debugging SMTP config.
  • Configuration quirks. The bundle reads standard doctrine config but also expects phpList-specific parameters (database prefix, bounce/administrator settings). Inspect CoreBundle::load/the bundle extension and Resources/config/*.yml for the actual parameter names; they are not documented on the README in depth.
  • Debugging tips.
    • bin/console doctrine:mapping:info — confirm Core entities are discovered.
    • bin/console debug:event-dispatcher — see which Core events you can hook.
    • bin/console lint:yaml vendor/phplist/core/src/Resources/config — catches broken vendor config after manual edits.
    • Enable Doctrine SQL logging in dev (doctrine.dbal.logging) to see exactly which repository call is failing.
  • Extension points to prefer. Symfony events fired by Core services, custom Command classes registered as services, and decorator services wrapping Core repositories. Avoid forking Core unless you plan to maintain a fork — the AGPL permits it, but the low upstream activity makes divergence expensive.
  • Version constraints are the #1 install blocker. If Composer reports conflicts on symfony/*, do not force-update Core; create a separate project pinned to the Symfony version the alpha supports, or contribute an upgrade. Mixing Core with Symfony 6+ components is a recipe for runtime type errors.
  • PHP version. Core was written for PHP 7.x-era type signatures. Running under PHP 8.1+ may surface deprecation warnings and, in some paths, ReturnTypeWillChange/mixed issues in vendored code; test thoroughly rather than assuming the alpha addressed compatibility.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core