PHP code example of phillarmonic / syncopate-bundle
1. Go to this page and download the library: Download phillarmonic/syncopate-bundle 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/ */
namespace App\Entity;
use Phillarmonic\SyncopateBundle\Attribute\Entity;
use Phillarmonic\SyncopateBundle\Attribute\Field;
use Phillarmonic\SyncopateBundle\Model\EntityDefinition;
use Phillarmonic\SyncopateBundle\Trait\EntityTrait;
#[Entity(name: 'product', idGenerator: EntityDefinition::ID_TYPE_UUID)]
class Product
{
use EntityTrait; // Include the EntityTrait to add array conversion methods
public ?string $id = null;
#[Field(type: 'string', indexed: true,
// Get all fields
$allFields = $product->toArray();
// Get only specific fields
$simpleData = $product->extract(fields: ['name', 'price']);
// Get all fields except specified ones
$withoutDescription = $product->extractExcept(exclude: ['description']);
// Get fields with custom key mapping
$renamedFields = $product->toArray(
fields: null,
exclude: [],
mapping: [
'name' => 'productName',
'price' => 'cost'
]
);
// Result: ['id' => '123', 'productName' => 'Product Name', 'cost' => 19.99, ...]
namespace App\Entity;
use Phillarmonic\SyncopateBundle\Attribute\Entity;
use Phillarmonic\SyncopateBundle\Attribute\Field;
use Phillarmonic\SyncopateBundle\Attribute\Relationship;
use Phillarmonic\SyncopateBundle\Trait\EntityTrait;
use DateTimeInterface;
#[Entity]
class Post
{
use EntityTrait;
#[Field]
private ?int $id = null;
#[Field(appedBy: 'post',
cascade: Relationship::CASCADE_REMOVE
)]
private array $comments = [];
// ... getters and setters
}
#[Entity]
class Comment
{
use EntityTrait;
#[Field]
private ?int $id = null;
#[Field(
namespace App\Repository;
use App\Entity\Product;
use Phillarmonic\SyncopateBundle\Repository\EntityRepository;
class ProductRepository extends EntityRepository
{
/**
* Find products in a specific price range
*/
public function findByPriceRange(float $minPrice, float $maxPrice): array
{
return $this->createQueryBuilder()
->gte(field: 'price', value: $minPrice)
->lte(field: 'price', value: $maxPrice)
->orderBy(field: 'price', direction: 'ASC')
->getResult();
}
/**
* Find featured products
*/
public function findFeaturedProducts(int $limit = 5): array
{
return $this->createQueryBuilder()
->eq(field: 'featured', value: true)
->gt(field: 'stock', value: 0)
->orderBy(field: 'price', direction: 'ASC')
->limit(limit: $limit)
->getResult();
}
/**
* Get products formatted for API response
*/
public function getProductsForApi(): array
{
$products = $this->findAll();
return array_map(function(Product $product) {
return $product->toArray(
mapping: [
'id' => 'productId',
'price' => 'unitPrice',
'stock' => 'availableQuantity'
]
);
}, $products);
}
/**
* Count products by category using optimized count API
*/
public function countByCategory(string $category): int
{
return $this->createQueryBuilder()
->eq(field: 'category', value: $category)
->count();
}
}
namespace App\Entity;
use App\Repository\ProductRepository;
use Phillarmonic\SyncopateBundle\Attribute\Entity;
use Phillarmonic\SyncopateBundle\Attribute\Field;
use Phillarmonic\SyncopateBundle\Model\EntityDefinition;
use Phillarmonic\SyncopateBundle\Trait\EntityTrait;
#[Entity(
name: 'product',
idGenerator: EntityDefinition::ID_TYPE_UUID,
repositoryClass: ProductRepository::class
)]
class Product
{
use EntityTrait;
// ... property definitions
}
// In a controller or service
$repository = $this->repositoryFactory->getRepository(Product::class);
// Use custom repository methods
$featuredProducts = $repository->findFeaturedProducts(limit: 3);
$midRangeProducts = $repository->findByPriceRange(minPrice: 20, maxPrice: 50);
// Get API-formatted products
$apiProducts = $repository->getProductsForApi();
// Get count of products in a category
$electronicsCount = $repository->countByCategory('electronics');
namespace App\Controller;
use App\Entity\Product;
use Phillarmonic\SyncopateBundle\Repository\EntityRepositoryFactory;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ProductController extends AbstractController
{
private EntityRepositoryFactory $repositoryFactory;
public function __construct(EntityRepositoryFactory $repositoryFactory)
{
$this->repositoryFactory = $repositoryFactory;
}
#[Route('/products', name: 'product_list', methods: ['GET'])]
public function list(): Response
{
$repository = $this->repositoryFactory->getRepository(Product::class);
$products = $repository->findAll();
// Convert all products to arrays for JSON response
$productsArray = array_map(fn($product) => $product->toArray(), $products);
return $this->json($productsArray);
}
#[Route('/products/count', name: 'product_count', methods: ['GET'])]
public function count(): Response
{
$repository = $this->repositoryFactory->getRepository(Product::class);
$totalCount = $repository->count();
return $this->json([
'total' => $totalCount
]);
}
#[Route('/products/{id}', name: 'product_show', methods: ['GET'])]
public function show(string $id): Response
{
$repository = $this->repositoryFactory->getRepository(Product::class);
$product = $repository->find(id: $id);
if (!$product) {
throw $this->createNotFoundException('Product not found');
}
// Only
// Count posts with comments from the last 7 days
$repository = $this->repositoryFactory->getRepository(Post::class);
$joinQueryBuilder = $repository->createJoinQueryBuilder();
$recentlyCommentedPostsCount = $joinQueryBuilder
->innerJoin(
entityType: 'comment',
localField: 'id',
foreignField: 'postId',
as: 'comments'
)
->gt(field: 'comments.createdAt', value: new \DateTime('-7 days'))
->count();
// Count users who have purchased a specific product
$repository = $this->repositoryFactory->getRepository(User::class);
$joinQueryBuilder = $repository->createJoinQueryBuilder();
$purchaserCount = $joinQueryBuilder
->innerJoin(
entityType: 'order',
localField: 'id',
foreignField: 'userId',
as: 'orders'
)
->innerJoin(
entityType: 'order_item',
localField: 'orders.id',
foreignField: 'orderId',
as: 'items'
)
->eq(field: 'items.productId', value: $productId)
->count();
$repository = $this->repositoryFactory->getRepository(Post::class);
$joinQueryBuilder = $repository->createJoinQueryBuilder();
$posts = $joinQueryBuilder
->innerJoin(
entityType: 'comment',
localField: 'id',
foreignField: 'postId',
as: 'comments'
)
->gt(field: 'comments.createdAt', value: new \DateTime('-7 days'))
->getJoinResult();
// Prepare posts for API response with renamed fields
$postsData = [];
foreach ($posts as $post) {
$postData = $post->extract(fields: ['title', 'content', 'createdAt']);
// Map comments to array with only necessary fields
$postData['comments'] = array_map(
fn($comment) => $comment->extract(fields: ['content']),
$post->comments
);
$postsData[] = $postData;
}
use Phillarmonic\SyncopateBundle\Service\SyncopateService;
class ProductService
{
private SyncopateService $syncopateService;
public function __construct(SyncopateService $syncopateService)
{
$this->syncopateService = $syncopateService;
}
public function getProductsByPriceRange(float $min, float $max): array
{
return $this->syncopateService->findBy(
entityClass: Product::class,
criteria: [],
orderBy: ['price' => 'ASC']
);
}
public function getProductCountByCriteria(array $criteria): int
{
return $this->syncopateService->count(
entityClass: Product::class,
criteria: $criteria
);
}
public function deleteProductWithRelations(string $id): bool
{
// Will automatically handle cascade delete based on relationship attributes
return $this->syncopateService->deleteById(
entityClass: Product::class,
id: $id,
enableCascade: true
);
}
public function getProductsForApi(): array
{
$products = $this->getProductsByPriceRange(min: 10, max: 100);
// Transform for API response using EntityTrait
return array_map(
fn($product) => $product->toArray(
mapping: [
'id' => 'productId',
'price' => 'unitPrice',
'stock' => 'availableQuantity'
]
),
$products
);
}
}
use Phillarmonic\SyncopateBundle\Exception\SyncopateApiException;
use Phillarmonic\SyncopateBundle\Exception\SyncopateValidationException;
use Phillarmonic\SyncopateBundle\Exception\SyncopateIntegrityConstraintException;
try {
$repository = $this->repositoryFactory->getRepository(Product::class);
$product = new Product();
$product->name = 'Test Product';
$product->sku = 'SKU123'; // Assuming SKU has a unique constraint
$repository->create($product);
} catch (SyncopateIntegrityConstraintException $e) {
// Handle unique constraint violations
$field = $e->getField(); // e.g., 'sku'
$value = $e->getValue(); // e.g., 'SKU123'
// Get user-friendly message
$friendlyMessage = $e->getFriendlyMessage();
// e.g., "The sku 'SKU123' is already in use. Please choose a different value."
return $this->json([
'error' => 'duplicate_entity',
'message' => $friendlyMessage,
'field' => $field
], 409);
} catch (SyncopateValidationException $e) {
// Handle validation errors with field-specific messages
$violations = $e->getViolations();
return $this->json([
'error' => 'validation_failed',
'message' => 'Please fix the following issues:',
'violations' => $violations
], 400);
} catch (SyncopateApiException $e) {
// Get detailed error information
$httpCode = $e->getCode();
$dbCode = $e->getDbCode(); // e.g., 'SY209'
$category = $e->getErrorCategory(); // e.g., 'Entity'
// Check if it's a client or server error
$isClientError = $e->isClientError();
// Check for specific error types
if ($e->isNotFoundError()) {
return $this->json([
'error' => 'not_found',
'message' => 'The requested resource could not be found.'
], 404);
}
return $this->json([
'error' => 'api_error',
'message' => $e->getMessage(),
'code' => $dbCode
], $httpCode);
}
try {
$product = $repository->find('non-existent-id');
} catch (SyncopateApiException $e) {
if ($e->isErrorType('SY200')) {
// Entity not found handling
}
}
try {
$repository->create($product);
} catch (SyncopateIntegrityConstraintException $e) {
// Specialized exception type with field information
$field = $e->getField(); // The field that caused the violation
$value = $e->getValue(); // The duplicated value
}
try {
$repository->create($invalidProduct);
} catch (SyncopateValidationException $e) {
// Get all violations as field => message array
$violations = $e->getViolations();
// Check for a specific field error
if ($e->hasViolation('price')) {
$priceError = $e->getViolation('price');
}
}
use Phillarmonic\SyncopateBundle\Util\DebugHelper;
// Enable detailed debug mode
DebugHelper::enableDebug();
// Set a custom log callback
DebugHelper::setLogCallback(function($message, $context) {
// Your custom logging implementation
$this->logger->debug($message, $context ?? []);
});
// Check for problematic data types in an array
$issues = DebugHelper::checkArrayForProblematicTypes($data);
if (!empty($issues)) {
foreach ($issues as $issue) {
echo "Issue at {$issue['path']}: {$issue['issue']}\n";
}
}
// Report memory usage
$memoryInfo = DebugHelper::getMemoryUsage();
echo "Memory used: {$memoryInfo['current']} (peak: {$memoryInfo['peak']})\n";
// Sanitize data for JSON encoding
$sanitizedData = DebugHelper::sanitizeForJson($data);
$json = DebugHelper::tryJsonEncode($sanitizedData);
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.