PHP code example of mediagone / doctrine-specifications
1. Go to this page and download the library: Download mediagone/doctrine-specifications library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
mediagone / doctrine-specifications example snippets
// Find all articles written by a given user
$articles = $repository->find(
ManyArticles::asEntity()
->postedByUser($userId)
);
// Find all published articles in a given category
$articles = $repository->find(
ManyArticles::asEntity()
->published()
->inCategory($categoryId)
->orderedByDateDesc()
->paginate($pageNumber, $itemsPerPage)
);
abstract class Specification
{
public function modifyBuilder(QueryBuilder $builder) : void { }
public function modifyQuery(Query $query) : void { }
}
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectEntity::specification(Article::class, 'article'),
);
}
public function postedByUser(UserId $userId) : self
{
$this->whereFieldEqual('article.user', 'userId', $userId);
return $this;
}
public function orderedAlphabetically() : self
{
$this->orderResultsByAsc('article.title');
return $this;
}
public function maxCount(int $count) : self
{
$this->limitResultsMaxCount($count);
return $this;
}
}
namespace App\Blog\Article\Query; // Example namespace, choose what fits best to your project
use Mediagone\Doctrine\Specifications\SpecificationCompound;
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
// Put select specifications here (one or more)
);
}
// We'll add more specification methods here later
}
namespace App\Blog\Article\Query\Specifications; // Example namespace
use App\Blog\Article; // assumed FQCN of your entity
use Doctrine\ORM\QueryBuilder;
use Mediagone\Doctrine\Specifications\Specification;
final class SelectArticleEntity extends Specification
{
public function modifyBuilder(QueryBuilder $builder) : void
{
$builder->from(Article::class, 'article');
$builder->select('article');
}
}
...
use App\Blog\Article\Query\Specifications\SelectArticleEntity;
use Mediagone\Doctrine\Specifications\SpecificationRepositoryResult;
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
new SelectArticleEntity()
);
}
}
use App\Blog\Article;
use Mediagone\Doctrine\Specifications\SpecificationRepositoryResult;
use Mediagone\Doctrine\Specifications\Universal\SelectEntity;
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectEntity::specification(Article::class, 'article'), // from + select
);
}
}
final class FilterArticlePostedByUser extends Specification
{
private UserId $userId;
public function __construct(UserId $userId)
{
$this->userId = $userId;
}
public function modifyBuilder(QueryBuilder $builder) : void
{
$builder->addWhere('article.authorId = :authorId');
$builder->setParameter('authorId', $this->userId, 'app_userid');
}
}
final class ManyArticles extends SpecificationCompound
{
// ...
public function postedByUser(UserId $userId) : self
{
$this->addSpecification(new FilterArticlePostedByUser($userId));
return $this;
}
}
final class ManyArticles extends SpecificationCompound
{
// ...
public function postedByUser(UserId $userId) : self
{
$this->whereFieldEqual('article.user', 'userId', $userId);
return $this;
}
}
final class ManyArticles extends SpecificationCompound
{
// ...
public function orderedAlphabetically() : self
{
// equivalent to: $doctrineQuerybuilder->addOrderBy('article.title', 'ASC');
$this->orderResultsByAsc('article.title');
return $this;
}
public function maxCount(int $count) : self
{
// equivalent to: $doctrineQuerybuilder->setMaxResults($count);
$this->limitResultsMaxCount($count);
return $this;
}
}
use Mediagone\Doctrine\Specifications\SpecificationRepository;
$repository = new SpecificationRepository($doctrineEntityManager);
$articles = $repository->find(
ManyArticles::asEntity()
->postedByUser($userId)
->orderedAlphabetically()
->maxCount(5)
);
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
// Return results as Article instances
SelectEntity::specification(Article::class, 'article')
);
}
public static function asModel() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
// Return results as ArticleModel instances
SelectReadModel::specification(Article::class, 'article', ArticleModel::class)
);
}
public static function asCount() : self
{
return new self(
SpecificationRepositoryResult::SINGLE_SCALAR,
// Return the number of results
SelectCount::specification(Article::class, 'article')
);
}
// some filtering methods...
}
$articleCount = $repository->find(
ManyArticles::asCount() // retrieve the count instead of entities
->postedByUser($userId)
->inCategory($category)
);
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectEntity::specification(Article::class, 'article')
// Join will be applied anytime
JoinLeft::specification('article.category', 'category'),
);
}
}
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectEntity::specification(Article::class, 'article')
);
}
public static function byCategoryName(string $categoryName) : self
{
$this->joinLeft('article.category', 'category');
$this->whereFieldEqual('category.name', 'cateName', $categoryName);
}
}
final class ManyArticles extends SpecificationCompound
{
public static function asEntity() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectEntity::specification(Article::class, 'article'),
JoinLeft::specification('article.category', 'category') // Join declaration
);
}
public static function byCategoryName(string $categoryName) : self
{
// Ignored, since the join was already declared in the constructor,
// it would be the same if declared in another called method.
$this->joinLeft('article.category', 'category');
$this->whereFieldEqual('category.name', 'catName', $categoryName);
}
public static function byParentCategoryName(string $categoryName) : self
{
// Not ignored since it uses a different alias ("pcat").
$this->joinLeft('category.parent', 'pcat');
$this->whereFieldEqual('pcat.name', 'pcatName', $categoryName);
}
}
final class ArticleModel implements SpecificationReadModel
{
private int $id;
private string $title;
private string $content;
private int $categoryId;
private string $categoryName;
// Keep field list close to the constructor's definition that uses it.
public static function getDqlConstructorArguments(): array
{
return [
'article.id',
'article.title',
'article.content',
'category.id',
'category.name',
];
}
public function __construct(
int $id,
string $title,
string $content,
int $categoryId,
string $categoryName,
) {
$this->id = $id;
$this->title = $title;
$this->content = $content;
$this->categoryId = $categoryId;
$this->categoryName = $categoryName;
}
}
final class ManyArticles extends SpecificationCompound
{
public static function asModel() : self
{
return new self(
SpecificationRepositoryResult::MANY_OBJECTS,
SelectReadModel::specification(Article::class, 'article', ArticleModel::class),
JoinLeft::specification('article.category', 'category') // Join declaration
);
}
// ...
}
final class ManyArticles extends SpecificationCompound
{
public function getEntityManager(ManagerRegistry $registry) : EntityManager
{
return $registry->getManagerForClass(Article::class);
}
}
public function getEntityManager(ManagerRegistry $registry) : EntityManager
{
return $registry->getManager('secondary');
}
use Mediagone\Doctrine\Specifications\Universal\WhereFieldEqual;
final class ManyArticles extends SpecificationCompound
{
// ...
public function postedByUser(UserId $userId) : self
{
// the following line
$this->whereFieldEqual('article.authorId', 'authorId', $userId, 'app_userid');
// is equivalent to
$this->addSpecification(WhereFieldEqual::specification('article.authorId', 'authorId', $userId, 'app_userid'));
return $this;
}
}
$pageNumber = 2;
$articlesPerPage = 10;
$articles = $repository->find(
ManyArticles::asEntity()
->postedByUser($userId)
->inCategory($category)
// Add results specifications separately (LimitResultsMaxCount and LimitResultsOffset)
->maxResult($articlesPerPage)
->resultOffset(($pageNumber - 1) * $articlesPerPage)
// Or use the pagination specification (LimitResultsPaginate)
->paginate($pageNumber, $articlesPerPage)
);
use Doctrine\ORM\QueryBuilder;
use Mediagone\Doctrine\Specifications\SpecificationCompound;
final class ManyArticles extends SpecificationCompound
{
// ...
public function postedByOneOfBothUsers(UserId $userId, UserId $userId2) : self
{
$this->modifyBuilder(static function(QueryBuilder $builder) use ($userId, $userId2) {
$builder
->andWhere('article.authorId = :authorId OR article.authorId = :authorId2')
->setParameter('authorId', $userId)
->setParameter('authorId2', $userId2)
;
});
return $this;
}
}
$articles = $repository->find(
ManyArticles::asEntity()
->published()
->postedByUser($userId)
->dumpDQL() // <--- equivalent of dump($query->getDQL());
->dumpSQL() // <--- equivalent of dump($query->getSQL());
);