Untitled

mail@pastecode.io avatar
unknown
plain_text
7 months ago
11 kB
3
Indexable
Never
    public function processElementPlacementOnDoc(Deed $deed, Collection $deedDocuments): Fpdi
    {
        $pdf = new Fpdi('P');

        foreach ($deedDocuments as $deedDocument) {
            $deedElements = $this->getDeedElements($deed->id, $deedDocument->id);

            $tempPdfFilePath = tempnam(sys_get_temp_dir(), 'deed_');
            $tempPdfContent = file_get_contents($deedDocument->path);
            file_put_contents($tempPdfFilePath, $tempPdfContent);

            $pageCount = $pdf->setSourceFile($tempPdfFilePath);

            for ($pageNumber = 1; $pageNumber <= $pageCount; $pageNumber++) {
                $this->injectElementsOnPage($pdf, $deedElements, $pageNumber);
            }

            unlink($tempPdfFilePath);
        }

        return $pdf;
    }

    /**
     * @return mixed
     */
    protected function getDeedElements(int $deedId, int $deedDocumentId): Collection
    {
        return DeedElement::where([
            'deed_id' => $deedId,
            'deed_document_id' => $deedDocumentId,
        ])->get();
    }

    /**
     * @throws GenericErrorException
     * @throws PdfParserException
     * @throws PdfReaderException
     * @throws CrossReferenceException
     * @throws FilterException
     * @throws PdfTypeException
     * @throws Exception
     */
    private function injectElementsOnPage(Fpdi $pdf, Collection $deed_elements, int $pageNumber): void
    {

        $templateId = $pdf->importPage($pageNumber);

        $size = $pdf->getTemplateSize($templateId);

        $pdf->AddPage(Arr::get($size, 'orientation'), [Arr::get($size, 'width'), Arr::get($size, 'height')]);
        $pdf->SetAutoPageBreak(0, 0);

        $pdf->useTemplate($templateId, 0, 0, Arr::get($size, 'width'), Arr::get($size, 'height'), true);

        $elementsOnPage = $this->pdfService->getCurrentPageElement($deed_elements->toArray(), $pageNumber);

        foreach ($elementsOnPage as $element) {

            $this->pdfService->addElementByType($pdf, ElementType::tryFrom(Arr::get($element, 'element_type')), $element);
        }
    }

    public function download(string $modifiedFilePath): BinaryFileResponse
    {

        $response = new BinaryFileResponse($modifiedFilePath);
        $response->headers->set('Content-Type', 'application/pdf');
        $response->headers->set('Content-Disposition', 'attachment; filename="modified_deed.pdf"');

        return $response;
    }

    public function getCurrentPageElement(array $elements, int $pageNumber): array
    {

        return array_filter($elements, function ($element) use ($pageNumber) {

            $element = $element['response_meta'];

            return $element['page'] == $pageNumber;
        });
    }

    /**
     * @throws Exception
     */
    public function addElementByType(Fpdi $pdf, ElementType $element_type, array $element_meta): void
    {

        $element_data = Arr::get($element_meta, 'response_meta');

        $x = Arr::get($element_data, 'cord.x');
        $y = Arr::get($element_data, 'cord.y');
        $width = Arr::get($element_data, 'area.width', '');
        $height = Arr::get($element_data, 'area.height', '');

        $element = new Element($pdf);

        match ($element_type) {
            ElementType::TEXT,ElementType::DROPDOWN, ElementType::DATE => $element->addTextElement($x, $y, $width, $height, Arr::get($element_data, 'value'), Arr::get($element_data, 'font_family'), Arr::get($element_data, 'font_size')),
            ElementType::STAMP,ElementType::INITIAL, ElementType::SIGNATURE => $element->addImageElement($x, $y, $width, $height, $element_data),
            ElementType::CHECKBOX => $element->addCheckBoxes($x, $y, Arr::get($element_data, 'is_checked')),
            ElementType::RADIO => $element->addRadioButtons($x, $y, Arr::get($element_data, 'options')),
            default => throw new Exception('Invalid element type', code: Response::HTTP_BAD_REQUEST)
        };

    }

<?php

namespace App\Services\Pdf;

use App\DTO\Coordinate;
use App\DTO\Dimension;
use App\Enums\SignatureType;
use Illuminate\Support\Arr;
use setasign\Fpdi\Fpdi;

class Element
{
    private Fpdi $pdf;

    private string $font_family = 'Arial';

    private int $font_size = 12;

    public function __construct(Fpdi $pdf)
    {
        $this->pdf = $pdf;
    }

    public function addImageElement(int $x, int $y, float $width, float $height, array $element_data): void
    {
        //        if it is text type signature and initial then call textElement
        if (Arr::get($element_data, 'type') === SignatureType::Text->value) {
            // Call addTextElement and return
            $this->addTextElement($x, $y, $width, $height, Arr::get($element_data, 'value'), Arr::get($element_data, 'font_family') ?? $this->font_family, Arr::get($element_data, 'font_size') ?? $this->font_size);

            return;
        }

        $coordinate = $this->calculateCoordinates($x, $y);
        $dimension = $this->calculateDimension($height, $width);

        // Assuming $img_src needs to be extracted from $element_data
        $img_src = Arr::get($element_data, 'img_src', ''); // Adjust this based on your actual data structure

        $this->pdf->Image(
            $img_src,
            $coordinate->x,
            $coordinate->y,
            $dimension->width,
            $dimension->height
        );
    }

    public function addTextElement(float $x, float $y, float $width, float $height, string $text, ?string $font_family, ?int $font_size): void
    {
        $coordinate = $this->calculateCoordinates($x, $y);

        $dimension = $this->calculateDimension($height, $width);

        $this->setPdfProperties($font_family, $font_size);

        $this->pdf->SetXY($coordinate->x, $coordinate->y);
        $this->pdf->MultiCell(
            $dimension->width,
            $dimension->height,
            $text,
            1,
            'C',
            false
        );
    }

    private function calculateCoordinates(float $x, float $y): Coordinate
    {

        $x = $x * 25.4 / 72;
        $y = $y * 25.4 / 72;

        return make_dto(Coordinate::class, ['x' => $x, 'y' => $y]);
    }

    /**
     * @return float[]
     */
    private function calculateDimension(float $height, float $width): Dimension
    {

        $height = $height * 25.4 / 72;
        $width = $width * 25.4 / 72;

        return make_dto(Dimension::class, ['width' => $width, 'height' => $height]);

    }

    private function setPdfProperties(?string $font_family, ?int $font_size): void
    {
        $this->pdf->SetFont($font_family ?? $this->font_family, '', $font_size ?? $this->font_size);
        // Additional properties specific to elements can be set here if necessary
    }

    //    public function addCheckBoxes(int $x, int $y, bool $is_checked): void
    //    {
    //        $coordinate = $this->calculateCoordinates($x, $y);
    //
    //        $checkboxHeight = 5; // Define the reduced height of the checkbox
    //        $checkboxWidth = 5;  // Define the reduced width of the checkbox
    //        $checkboxSpacing = 5; // Define the spacing between checkboxes
    //        $textOffsetY = 3.5; // Adjust the Y-axis positioning for the text
    //
    //        $y = $coordinate->y;
    //
    //        // Draw a smaller checkbox at each option's specified coordinates
    //        $this->pdf->Rect($coordinate->x, $y, $checkboxWidth, $checkboxHeight);
    ////        $this->pdf->Text($coordinate->x + $checkboxWidth + 2, $y + $textOffsetY, ''); // Add option label with adjusted Y-axis
    //
    //        $y += $checkboxHeight + $checkboxSpacing; // Move to the next line for the next checkbox
    //
    //    }

        public function addCheckBoxes(int $x, int $y, bool $is_checked, float $width = 20, float $height = 20): void
    {
        $coordinate = $this->calculateCoordinates($x, $y);
    
        $checkboxWidth = $width * 25.4 / 72;
        $checkboxHeight = $height * 25.4 / 72;
    
        // Draw a checkbox at the specified coordinates
        $this->pdf->Rect($coordinate->x, $coordinate->y, $checkboxWidth, $checkboxHeight);
    
        // If $is_checked is true, draw a proportional checkmark inside the checkbox
        if ($is_checked) {
            $this->drawProportionalCheckmark($coordinate->x, $coordinate->y, $checkboxWidth, $checkboxHeight);
        }
    }
    
    private function drawProportionalCheckmark(float $x, float $y, float $width, float $height): void
    {
        // Calculate checkmark size and position
        $checkSize = min($width, $height) * 0.8; // Adjust the proportion as needed
        $xCenter = $x + ($width - $checkSize) / 2;
        $yCenter = $y + ($height - $checkSize) / 2;
    
        // Calculate checkmark coordinates
        $x1 = $xCenter + 0.2 * $checkSize;
        $y1 = $yCenter + 0.5 * $checkSize;
        $x2 = $xCenter + 0.4 * $checkSize;
        $y2 = $yCenter + 0.7 * $checkSize;
        $x3 = $xCenter + 0.8 * $checkSize;
        $y3 = $yCenter + 0.3 * $checkSize;
    
        // Draw the checkmark
        $this->pdf->Line($x1, $y1, $x2, $y2);
        $this->pdf->Line($x2, $y2, $x3, $y3);
    }
    
    
    

    public function addRadioButtons(int $x, int $y, array $options): void
    {
        $coordinate = $this->calculateCoordinates($x, $y);

        $radioDiameter = 5;    // Define the diameter of the radio button
        $radioSpacing = 7;    // Define the spacing between radio buttons
        $textOffsetX = 1; // Adjust this value to align text with the radio button horizontally
        $textOffsetY = 1; // Adjust this value to align text with the radio button vertically
        $y = $coordinate->y;

        foreach ($options as $option) {
            // Draw the circle for the radio button
            $this->drawRadioCircle($coordinate->x, $y, $radioDiameter);
            // Add text for the radio button option
            $this->pdf->Text(x: $coordinate->x + $radioDiameter + $textOffsetX, y: $y + $textOffsetY, txt: $option);
            $y += $radioSpacing; // Move to the next line for the next radio button
        }
    }

    private function drawRadioCircle(int $x, int $y, int $diameter): void
    {
        $segments = 360; // Number of segments to approximate a circle

        for ($i = 0; $i < $segments; $i++) {
            $angle = ($i / $segments) * 2 * M_PI;
            $nextAngle = (($i + 1) / $segments) * 2 * M_PI;

            $x1 = $x + ($diameter / 2 * cos($angle));
            $y1 = $y + ($diameter / 2 * sin($angle));
            $x2 = $x + ($diameter / 2 * cos($nextAngle));
            $y2 = $y + ($diameter / 2 * sin($nextAngle));

            $this->pdf->Line($x1, $y1, $x2, $y2); // Draw a line segment
        }
    }
}
Leave a Comment