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
27 changes: 20 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ on:
permissions:
contents: read

env:
XDEBUG_MODE: coverage

Comment thread
javihgil marked this conversation as resolved.
jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -24,7 +27,8 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
# extensions: intl #optional
extensions: sqlite3, pdo_sqlite
coverage: xdebug
ini-values: "post_max_size=256M" #optional

- name: Check PHP Version
Expand All @@ -49,14 +53,23 @@ jobs:
run: ./vendor/bin/phpstan analyse

- name: Run tests
run: ./vendor/bin/phpunit --coverage-text --coverage-html=.phpunit.cache/html-report
run: ./vendor/bin/phpunit

- name: Code Style check
run: ./vendor/bin/php-cs-fixer fix -v --diff --dry-run

- name: phpunit-coverage-badge
uses: timkrase/phpunit-coverage-badge@v1.2.1
- name: Check coverage report
id: coverage_report
run: |
if [ -f clover.xml ]; then
echo "has_clover=true" >> "$GITHUB_OUTPUT"
else
echo "has_clover=false" >> "$GITHUB_OUTPUT"
fi

- name: Upload coverage to Codecov
if: matrix.composer-prefer == '' && steps.coverage_report.outputs.has_clover == 'true'
uses: codecov/codecov-action@v5
with:
push_badge: true
coverage_badge_path: .github/badges/coverage.svg
repo_token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.CODECOV_TOKEN }}
files: clover.xml
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ composer.lock
.coverage-report/
.php-cs-fixer.cache
.php_cs.cache
.phpunit.result.cache
.phpunit.result.cache
.phpunit.cache
clover.xml
11 changes: 11 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Contributing

Use the standard package commands before sending changes:

```bash
composer fix
composer test
composer test-bc
```

[Report issues](https://github.com/softspring/user-bundle/issues) and [send Pull Requests](https://github.com/softspring/user-bundle/pulls)
54 changes: 54 additions & 0 deletions FEATURES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# User Bundle Features

Functional definition for `softspring/user-bundle`.

## Purpose

- Provide a reusable user layer for Symfony applications.
- Cover common user lifecycle workflows without forcing a fixed application model.
- Offer extension points so projects can adapt behavior and persistence.

## Main Features

- Base user model contracts and composable traits for:
- identifiers
- password support
- enabled status
- name and surname
- locale
- avatar
- admin/super-admin roles
- User account workflows:
- login
- registration
- email confirmation
- password reset request and reset confirmation
- account settings update (email, username, password)
- Administration workflows:
- users management
- administrators management
- invitations
- access history
- Optional OAuth integration points.
- Doctrine filters for user/admin visibility.
- Mailers, MIME classes, events, and manipulators for user lifecycle actions.
- Console commands for common user and admin operations.

## Integration And Extension

- Integrates with Symfony Security, Twig, Validator, Translation, and HTTP components.
- Integrates with Doctrine ORM/Doctrine Bundle.
- Integrates with Softspring packages such as:
- `permissions-bundle`
- `crudl-controller`
- `twig-extra-bundle`
- `doctrine-query-filters`
- `doctrine-target-entity-resolver`
- Allows custom application entities by implementing bundle interfaces and composing provided traits.
- Supports custom service overrides for controllers, managers, and mailers through Symfony configuration.

## Expected Capabilities

- Must work with the supported dependency matrix of this line, including Symfony `6.4`, `7.x`, and `8.x`.
- Must keep both regular and lowest dependency validation workflows working (`composer test` and `composer test-bc`).
- Must keep user-facing and admin-facing user workflows stable across minor releases in the same line.
26 changes: 12 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
# User Bundle

![Latest Stable](https://img.shields.io/packagist/v/softspring/user-bundle?label=stable&style=flat-square)
![Latest Unstable](https://img.shields.io/packagist/v/softspring/user-bundle?label=unstable&style=flat-square&include_prereleases)
![License](https://img.shields.io/packagist/l/softspring/user-bundle?style=flat-square)
![PHP Version](https://img.shields.io/packagist/dependency-v/softspring/user-bundle/php?style=flat-square)
![Downloads](https://img.shields.io/packagist/dt/softspring/user-bundle?style=flat-square)
[![Latest Stable](https://img.shields.io/packagist/v/softspring/user-bundle?label=stable&style=flat-square)](https://github.com/softspring/user-bundle/releases)
[![Latest Unstable](https://img.shields.io/packagist/v/softspring/user-bundle?label=unstable&style=flat-square&include_prereleases)](https://github.com/softspring/user-bundle/releases)
[![License](https://img.shields.io/packagist/l/softspring/user-bundle?style=flat-square)](https://github.com/softspring/user-bundle/blob/6.0/LICENSE)
[![PHP Version](https://img.shields.io/packagist/dependency-v/softspring/user-bundle/php?style=flat-square)](https://github.com/softspring/user-bundle/blob/6.0/composer.json)
[![Downloads](https://img.shields.io/packagist/dt/softspring/user-bundle?style=flat-square)](https://packagist.org/packages/softspring/user-bundle)
[![CI](https://img.shields.io/github/actions/workflow/status/softspring/user-bundle/ci.yml?branch=6.0&style=flat-square&label=CI)](https://github.com/softspring/user-bundle/actions/workflows/ci.yml)
![Coverage](https://raw.githubusercontent.com/softspring/user-bundle/6.0/.github/badges/coverage.svg)
[![Coverage](https://img.shields.io/codecov/c/github/softspring/user-bundle?branch=6.0&style=flat-square)](https://codecov.io/gh/softspring/user-bundle)

A complete user bundle
A complete user bundle for Symfony applications, including user authentication flows, settings pages, invitations, and admin user management screens.

## Armonic

Expand All @@ -20,16 +20,14 @@ This package is part of [Armonic](https://softspring.es/en/armonic).

## Contributing

Use the standard package commands before sending changes:

```bash
composer fix
composer test
composer test-bc
```
See [CONTRIBUTING.md](CONTRIBUTING.md).

[Report issues](https://github.com/softspring/user-bundle/issues) and [send Pull Requests](https://github.com/softspring/user-bundle/pulls)

## Security

See [SECURITY.md](SECURITY.md).

## License

This package is free and released under the [AGPL-3.0 license](LICENSE).
29 changes: 29 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Security Policy

## Supported Versions

Only the current stable line and the current development line receive security updates.

| Version | Supported |
| ------- | --------- |
| 6.0.x | Yes |
| 5.5.x | Yes |
| < 5.5 | No |

## Reporting a Vulnerability

Please report security issues privately.

Do not open public GitHub issues for security vulnerabilities.

Send the report to: `security@softspring.es`

Please include:

- affected package
- affected version
- steps to reproduce
- impact description
- any suggested fix or mitigation if available

We will review the report, confirm whether it is a valid vulnerability, and contact you with the next steps.
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@
"softspring/doctrine-templates": "^6.0@dev",
"softspring/mailer-bundle": "^6.0@dev",
"softspring/media-bundle": "^6.0@dev",
"phpunit/phpunit": "^12.5",
"symfony/browser-kit": "^6.4 || ^7.4 || ^8.0",
"symfony/css-selector": "^6.4 || ^7.4 || ^8.0",
"symfony/dom-crawler": "^6.4 || ^7.4 || ^8.0",
"symfony/form": "^6.4 || ^7.4 || ^8.0",
"symfony/http-client": "^6.4 || ^7.4 || ^8.0",
"symfony/mailer": "^6.4 || ^7.4 || ^8.0",
"symfony/phpunit-bridge": "^6.4 || ^7.4 || ^8.0"
"symfony/var-exporter": "^6.4 || ^7.4"
},
"suggest": {
"hwi/oauth-bundle": "Integrate oauth clients",
Expand Down Expand Up @@ -85,8 +86,8 @@
],
"run-tests": [
"composer validate --strict --no-check-lock --ansi",
Comment thread
javihgil marked this conversation as resolved.
"# XDEBUG_MODE=coverage vendor/bin/phpunit",
"vendor/bin/rector process src tests --dry-run",
"XDEBUG_MODE=coverage vendor/bin/phpunit",
"vendor/bin/rector process src tests --dry-run --debug",
"vendor/bin/phpstan analyse src tests --level 5",
"vendor/bin/php-cs-fixer fix --dry-run --diff",
"vendor/bin/yaml-lint .github/ -vvv --parse-tags",
Expand Down
5 changes: 5 additions & 0 deletions config/services/mailer.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

Softspring\UserBundle\Mailer\UserMailerInterface:
class: Softspring\UserBundle\Mailer\UserMailer

Expand Down
25 changes: 21 additions & 4 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

<!-- https://phpunit.de/manual/current/en/appendixes.configuration.html -->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/bin/.phpunit/phpunit/phpunit.xsd"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
cacheDirectory=".phpunit.cache"
colors="true"
bootstrap="tests/bootstrap.php">

<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="-1" />
<ini name="error_reporting" value="E_ALL &amp; ~E_DEPRECATED &amp; ~E_USER_DEPRECATED" />
<server name="APP_ENV" value="test" force="true" />
<server name="APP_DEBUG" value="false" force="true" />
<server name="SHELL_VERBOSITY" value="-1" />
Expand All @@ -21,16 +22,32 @@

<testsuites>
<testsuite name="UserBundle Test Suite">
<directory>tests/</directory>
<directory suffix="Test.php">tests</directory>
<exclude>tests/DataCollector/</exclude>
<exclude>tests/EventListener/</exclude>
<exclude>tests/Form/</exclude>
</testsuite>
</testsuites>

<coverage processUncoveredFiles="true">
<source ignoreIndirectDeprecations="true">
<include>
<directory suffix=".php">src</directory>
</include>
<exclude>
<directory>vendor</directory>
<directory>tests</directory>
</exclude>
</source>

<coverage>
<report>
<clover outputFile="clover.xml"/>
<html outputDirectory=".phpunit.cache/html-coverage"
lowUpperBound="50"
highLowerBound="90"/>
<text outputFile=".phpunit.cache/coverage.txt"
showUncoveredFiles="false"
showOnlySummary="true"/>
</report>
</coverage>
</phpunit>
4 changes: 2 additions & 2 deletions rector.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use Rector\Config\RectorConfig;
use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonySetList;
use Rector\Symfony\Symfony61\Rector\Class_\CommandConfigureToAttributeRector;
use Rector\ValueObject\PhpVersion;

return RectorConfig::configure()
Expand All @@ -23,5 +22,6 @@
->withPhpVersion(PhpVersion::PHP_84)
->withComposerBased(symfony: true)
->withSkip([
CommandConfigureToAttributeRector::class,
__DIR__.'/tests/Unit/Security/Authorization/Voter/AdminAdministratorsActionsVoterTest.php',
__DIR__.'/tests/Unit/Security/Authorization/Voter/SwitchUserVoterTest.php',
]);
3 changes: 2 additions & 1 deletion src/Command/CreateUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Softspring\UserBundle\Manipulator\UserManipulator;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'sfs:user:create')]
class CreateUserCommand extends Command
{
protected UserManipulator $userManipulator;
Expand All @@ -23,7 +25,6 @@ public function __construct(UserManipulator $userManipulator, ?string $name = nu

protected function configure(): void
{
$this->setName('sfs:user:create');
$this->addArgument('username', InputArgument::REQUIRED, 'Username');
$this->addArgument('email', InputArgument::REQUIRED, 'Email');
$this->addArgument('password', InputArgument::REQUIRED, 'Password');
Expand Down
3 changes: 2 additions & 1 deletion src/Command/InviteUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
namespace Softspring\UserBundle\Command;

use Softspring\UserBundle\Manipulator\UserInvitationManipulator;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'sfs:user:invite')]
class InviteUserCommand extends Command
{
protected UserInvitationManipulator $userInvitationManipulator;
Expand All @@ -22,7 +24,6 @@ public function __construct(UserInvitationManipulator $userInvitationManipulator

protected function configure(): void
{
$this->setName('sfs:user:invite');
$this->addArgument('email', InputArgument::REQUIRED, 'Email');
$this->addArgument('username', InputArgument::OPTIONAL, 'Username');
$this->addOption('role', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, 'Add user roles (comma separated)', []);
Expand Down
3 changes: 2 additions & 1 deletion src/Command/PromoteUserCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
use Softspring\UserBundle\Manager\UserManagerInterface;
use Softspring\UserBundle\Model\RolesAdminInterface;
use Softspring\UserBundle\Model\UserInterface;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'sfs:user:promote')]
class PromoteUserCommand extends Command
{
protected UserManagerInterface $userManager;
Expand All @@ -24,7 +26,6 @@ public function __construct(UserManagerInterface $userManager, ?string $name = n

protected function configure(): void
{
$this->setName('sfs:user:promote');
$this->addArgument('identifier', InputArgument::REQUIRED, 'User identifier (username or email)');
$this->addOption('super-admin', 's', InputOption::VALUE_NONE, 'User is super admin');
}
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/SfsUserExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public function load(array $configs, ContainerBuilder $container): void
$loader->load('services/data_fixtures.yaml');
}

if (class_exists(MailerInterface::class)) {
if (interface_exists(MailerInterface::class)) {
$loader->load('services/mailer.yaml');
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Doctrine/Filter/AdminFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

class AdminFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, string $targetTableAlias): string
public function addFilterConstraint(ClassMetadata $targetEntity, mixed $targetTableAlias): string
{
if (!$targetEntity->getReflectionClass()->implementsInterface(RolesAdminInterface::class)) {
return '';
Expand Down
Loading
Loading