symfony-doctrine-persistence — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited symfony-doctrine-persistence (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
You are an expert in Doctrine ORM within Symfony hexagonal architecture.
#[ORM\Entity] or annotations on domain entitiesInfrastructure/{Module}/Persistence/Mapping/$connection->executeQuery(), $connection->executeStatement(), NativeQuery, $connection->prepare(), or raw SQL strings anywhere in application code. Always use Doctrine QueryBuilder (ORM or DBAL), DQL, finder methods, or Criteria API. The only exception is Doctrine Migrations ($this->addSql()) which requires raw SQL by design.namespace App\Infrastructure\{Module}\Persistence;
use App\Domain\{Module}\Entity\{Entity};
use App\Domain\{Module}\Port\{Entity}RepositoryInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Messenger\MessageBusInterface;
final readonly class Doctrine{Entity}Repository implements {Entity}RepositoryInterface
{
public function __construct(
private EntityManagerInterface $entityManager,
private MessageBusInterface $eventBus,
) {
}
public function save({Entity} $entity): void
{
$this->entityManager->persist($entity);
$this->entityManager->flush();
foreach ($entity->pullDomainEvents() as $event) {
$this->eventBus->dispatch($event);
}
}
public function findById({Entity}Id $id): ?{Entity}
{
return $this->entityManager->find({Entity}::class, $id->value);
}
public function remove({Entity} $entity): void
{
$this->entityManager->remove($entity);
$this->entityManager->flush();
}
}<!-- src/Infrastructure/User/Persistence/Mapping/User.orm.xml -->
<doctrine-mapping>
<entity name="App\Domain\User\Entity\User" table="users">
<id name="id" type="string" column="id" />
<embedded name="email" class="App\Domain\User\ValueObject\Email" />
<field name="name" type="string" />
<field name="createdAt" type="datetime_immutable" column="created_at" />
</entity>
</doctrine-mapping>// Separate mapping class that maps to domain entity
// Configure in doctrine.yaml with mapping pathsAlways ask the user which strategy they prefer:
php bin/console doctrine:migrations:diff (generates from mapping)Native/raw SQL bypasses Doctrine's abstraction layers and creates several problems:
Flag these patterns as CRITICAL violations:
// FORBIDDEN — native SQL patterns
$connection->executeQuery('SELECT ...');
$connection->executeStatement('INSERT ...');
$connection->prepare('SELECT ...');
$connection->exec('DROP ...');
$entityManager->getConnection()->executeQuery(...);
$entityManager->createNativeQuery(...);
$rsm = new ResultSetMapping();
// ALLOWED — Doctrine abstractions
$queryBuilder->select(...)->from(...)->where(...); // DBAL QueryBuilder
$entityManager->createQueryBuilder()->select('u')...; // ORM QueryBuilder
$entityManager->createQuery('SELECT u FROM User u'); // DQL
$repository->findBy([...]); // Finder methods
$repository->matching($criteria); // Criteria APISee references/ for detailed guides:
repository-patterns.md — Repository patterns and transaction managementmapping-patterns.md — XML mapping, embeddables, relationsmigration-workflow.md — Migration strategies and best practicesno-native-sql.md — Why native SQL is forbidden and how to use QueryBuilder instead~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.