Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ev Powerpoint Bundle Laravel Package

ev/ev-powerpoint-bundle

EV PowerPoint Bundle integrates PowerPoint (PPTX) generation into Symfony applications, providing services and configuration to create, style, and export presentations programmatically using PHP. Streamline report and slide deck generation with a bundle-friendly setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Reality check first. ev/ev-powerpoint-bundle is a Symfony2 bundle (EOL since 2018) that wraps PHPPowerPoint, which is itself abandoned and superseded by phpoffice/phppresentation. There is no ServiceProvider, no facade, no config/*.php — a Laravel app cannot composer require it cleanly, because its constraints drag in symfony/symfony ~2.x and PHP 5.x. So "getting started" in a Laravel codebase means one of two paths:

  1. Use the underlying library directly (recommended if you must have this API):
    composer require phpoffice/phppowerpoint
    
    PHPPowerPoint is PEAR-style (PHPPowerPoint_IOFactory), no namespaces, no PHP 8 support. Expect deprecation noise and test it hard before committing.
  2. Use the maintained fork — phpoffice/phppresentation. Same author lineage, same object model, namespaced, PHP 8 compatible:
    composer require phpoffice/phppresentation
    

Where to look first if you're evaluating the bundle source: EVPowerPointBundle.php (just a Bundle subclass), DependencyInjection/EVPowerPointExtension.php + Resources/config/services.yml (this is the entire value-add — a service alias around PHPPowerPoint), and then skip straight to the vendored PHPPowerPoint/ classes. There is essentially no bundle-specific logic to learn; the API is PHPPowerPoint.

First use case: generate a PPTX deck from Eloquent data and stream it as a download. That's the 90% case — monthly reports, sales summaries, exported dashboards.

// app/Services/Pptx/DeckBuilder.php
namespace App\Services\Pptx;

use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\IOFactory;
use PhpOffice\PhpPresentation\Style\Alignment;
use PhpOffice\PhpPresentation\Style\Color;

class DeckBuilder
{
    public function build(array $rows): string
    {
        $pres = new PhpPresentation();
        $pres->getLayout()->setDocumentLayout('screen16x9');

        $slide = $pres->getActiveSlide();
        $shape = $slide->createRichTextShape()
            ->setHeight(80)->setWidth(800)
            ->setOffsetX(50)->setOffsetY(40);
        $shape->getActiveParagraph()->getAlignment()->setHorizontal(Alignment::HORIZONTAL_LEFT);
        $shape->getActiveParagraph()->createTextRun('Q3 Summary')
            ->getFont()->setSize(28)->setBold(true)->setColor(new Color('FF1F3864'));

        foreach ($rows as $row) {
            $s = $pres->createSlide();
            $t = $s->createRichTextShape()->setHeight(600)->setWidth(800)
                ->setOffsetX(50)->setOffsetY(100);
            $t->getActiveParagraph()->createTextRun($row['title'])->getFont()->setSize(20);
        }

        $tmp = tempnam(sys_get_temp_dir(), 'deck_') . '.pptx';
        IOFactory::createWriter($pres, 'PowerPoint2007')->save($tmp);
        return $tmp;
    }
}
// app/Http/Controllers/ReportController.php
public function download(DeckBuilder $builder)
{
    $path = $builder->build(Report::latest()->take(10)->get()->toArray());
    return response()->download($path, 'report.pptx')->deleteFileAfterSend(true);
}

Implementation Patterns

Bind it as a singleton, don't new it inline. The bundle's only real gift is DI; replicate that in AppServiceProvider:

$this->app->singleton(DeckBuilder::class, fn () => new DeckBuilder());

Separate "model → slide data" from "slide data → PPTX". The deck builder should take plain arrays, never Eloquent models. This is the single biggest maintainability win — it lets you unit-test slide content without touching the writer, and swap PHPPowerPoint out later without rewriting business logic.

interface DeckSource { public function slides(): array; }

class MonthlyReportSource implements DeckSource
{
    public function __construct(private CarbonImmutable $month) {}

    public function slides(): array
    {
        return Order::whereBetween('created_at', [$this->month->startOfMonth(), $this->month->endOfMonth()])
            ->groupBy('region')
            ->get()
            ->map(fn ($g) => ['title' => $g->first()->region, 'value' => $g->sum('total')])
            ->all();
    }
}

Push generation to a queue for anything non-trivial. Presentation objects are fully in-memory and PHPExcel-lineage; a 40-slide deck with images will happily eat 100–200 MB. Pattern: dispatch a job, have it write to Storage::disk('s3'), then email a signed URL.

Storage::disk('s3')->put($key, file_get_contents($path));
unlink($path);

Templating beats construction. If your decks have real design (branded master slides, charts), building them shape-by-shape in code is miserable. Instead ship a .pptx template, unzip it, string-replace placeholders in ppt/slides/slideN.xml, and rezip. Ten lines of ZipArchive, preserves all formatting, and doesn't depend on an abandoned library at all:

$zip = new ZipArchive();
$zip->open($template);
for ($i = 0; $i < $zip->numFiles; $i++) {
    $name = $zip->getNameIndex($i);
    if (!str_starts_with($name, 'ppt/slides/slide')) continue;
    $xml = strtr($zip->getFromIndex($i), $replacements);
    $zip->addFromString($name, $xml);
}
$zip->close();

Reading is the weak half. PHPPowerPoint's reader handles simple files and chokes on anything with SmartArt, embedded media, or exotic layouts. For text extraction (indexing uploaded decks, for instance), unzip and strip_tags the <a:t> runs from ppt/slides/*.xml — more reliable than the reader, and no dependency.

Wrap the writer in a contract. DeckWriter interface with a PhpPowerPointWriter implementation and later a PhpPresentationWriter. When you migrate (you will), it's a one-line container swap.

Gotchas and Tips

  • Composer will fight you. The bundle's symfony/symfony constraint will not resolve against Laravel 9/10/11. If you genuinely want the code, composer require it in an isolated PHP 5.6/7.x project, or copy the relevant classes in manually. Do not add it to a modern composer.json.
  • The bundle is not the library. Everything useful lives in PHPPowerPoint. Treat the bundle as documentation of a service definition and nothing more — don't look for bundle-specific features.
  • Abandoned = unpatched. Packagist flags PHPPowerPoint as abandoned. No PHP 8.1+ fixes, no security response, and the PEAR-style classes break under strict deprecation handling. If you're on PHP 8, phpoffice/phppresentation is the only credible path; its API is nearly identical (createRichTextShape, createDrawingShape, createChart, IOFactory::createWriter) so porting is mechanical.
  • Output buffering bites you. If you echo the writer output directly from a controller, Laravel's middleware and any ob_start in your stack can corrupt the binary. Always write to a temp file and use response()->download() / streamDownload(), never inline output.
  • tempnam() returns a file; .pptx extension matters. Some PPTX writers infer the format from the extension. Create the file, append .pptx to the returned path, and clean up in a finally.
  • Memory. Call $pres->getActiveSlide() once per slide loop rather than re-fetching; avoid embedding large images; if you hit Allowed memory size exhausted, that's the library, not your code — chunk the deck and merge, or switch to the template-replacement approach.
  • Charts are the trap. createChart() in this lineage is brittle across PowerPoint/LibreOffice/Keynote. Verify output opens in all three before shipping; many teams end up rendering charts as images server-side and embedding them.
  • Debugging the Symfony side: if you're reading the bundle source for reference, bin/console debug:container ev in a Symfony 2 app reveals the service id — but there is no Laravel equivalent to configure, since there's no config tree worth honoring.
  • Extension point that actually exists: the DI service alias. In Laravel terms, that's your singleton() binding plus a DeckWriter interface. Build the abstraction now so the migration to phppresentation is a rewrite of one class, not fifty call sites.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route