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/ */

    

phillarmonic / syncopate-bundle example snippets


return [
    // ...
    Phillarmonic\SyncopateBundle\PhillarmonicSyncopateBundle::class => ['all' => true],
];



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 

$repository = $this->repositoryFactory->getRepository(Product::class);
$queryBuilder = $repository->createQueryBuilder();

$products = $queryBuilder
    ->gt(field: 'price', value: 20)
    ->lt(field: 'price', value: 100)
    ->contains(field: 'description', value: 'awesome')
    ->orderBy(field: 'price', direction: 'DESC')
    ->limit(limit: 10)
    ->offset(offset: 0)
    ->getResult();

// Convert results to arrays with custom field mapping
$productsArray = array_map(
    fn($product) => $product->toArray(
        mapping: [
            'name' => 'productName',
            'price' => 'cost'
        ]
    ),
    $products
);

// Simple count of all entities
$repository = $this->repositoryFactory->getRepository(Product::class);
$totalCount = $repository->count();

// Count with query builder filters
$queryBuilder = $repository->createQueryBuilder();
$inStockCount = $queryBuilder
    ->eq(field: 'inStock', value: true)
    ->gt(field: 'price', value: 50)
    ->count();

// Count with pagination info
$queryBuilder = $repository->createQueryBuilder();
$filteredCount = $queryBuilder
    ->contains(field: 'name', value: 'gaming')
    ->count();

$pageSize = 10;
$totalPages = ceil($filteredCount / $pageSize);

// 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);