SlideShare a Scribd company logo
1 of 68
Download to read offline
Simplifiez-vous les Design
  Patterns avec PHP 5.3
        Hugo Hamon – 12/07/12
Observateur

Dependency Injection

Inversion de Contrôle
Observer
Un sujet, l’objet
observable, émet un signal
à des modules qui jouent
le rôle d’observateurs.
Event Dispatcher
Le Dispatcheur est un objet
qui gère les connexions
entre le sujet observé et ses
observateurs (écouteurs).
# composer.json

{
    "require": {
        "php": ">=5.3.3",
        "symfony/event-dispatcher": "2.1.*"
    }
}
use SymfonyComponentEventDispatcherEvent;
use SymfonyComponentEventDispatcherEventDispatcher;
use AFUPArticleListener;

$dispatcher = new EventDispatcher();

// Déclaration des écouteurs
$listener1 = array(new ArticleListener(), 'onDelete');
$listener2 = array(new ArticleListener(), 'onSave');

// Enregistrement des écouteurs
$dispatcher->addListener('article.delete', $listener1);
$dispatcher->addListener('article.pre_save', $listener2);

// Notification des écouteurs
$dispatcher->dispatch('article.pre_save', new Event());
Mise en Pratique
use AFUPModelArticle;

$article = new Article();
$article->setTitle('AFUP Design Patterns');
$article->setContent('Some **content**');
$article->save();

echo $article->getHtmlContent();
<p>
      Some <strong>content</strong>
</p>
namespace AFUPModel;

use PropelRuntimeConnectionConnectionInterface;
use dflydevmarkdownMarkdownParser;

class Article extends AFUPModelBaseArticle
{
    public function save(ConnectionInterface $con = null)
    {
        $parser = new MarkdownParser();
        $html = $parser->transformMarkdown($this->getContent());
        $this->setHtmlContent($html);

        $ret = parent::save($con);

        $this->updateLuceneIndex();

        return $ret;
    }
}
Le Sujet
   Observé
namespace AFUPModel;

use SymfonyComponentEventDispatcherEventDispatcher;
use AFUPModelBaseArticle as BaseArticle;

class Article extends BaseArticle
{
    private $dispatcher;

    public function setDispatcher(EventDispatcher $dispatcher)
    {
        $this->dispatcher = $dispatcher;
    }
}
namespace AFUPModel;

// ...
use PropelRuntimeConnectionConnectionInterface;
use AFUPEventArticleEvent;

class Article extends BaseArticle
{
    // ...
    public function save(ConnectionInterface $con = null)
    {
        $event = new ArticleEvent($this);
        $this->dispatcher->dispatch('article.pre_save', $event);

         $ret = parent::save($con);
         $this->dispatcher->dispatch('article.post_save', $event);

         return $ret;
    }
}
Propager un
   Evénement
namespace AFUPEvent;

use SymfonyComponentEventDispatcherEvent;
use AFUPModelArticle;

class ArticleEvent extends Event
{
    private $article;

    public function __construct(Article $article)
    {
        $this->article = $article;
    }

    public function getArticle()
    {
        return $this->article;
    }
}
Ajouter des
   écouteurs
namespace AFUPListener;

use AFUPEventArticleEvent;
use dflydevmarkdownMarkdownParser;

class ArticleListener
{
    public function onPreSave(ArticleEvent $event)
    {
        $article = $event->getArticle();
        $markdown = $article->getContent();

        $parser = new MarkdownParser();
        $html = $parser->transformMarkdown($markdown);
        $article->setHtmlContent($html);
    }
}
namespace AFUPListener;

use   ZendSearchLuceneDocument;
use   ZendSearchLuceneDocumentField;
use   AFUPEventArticleEvent;
use   AFUPModelArticlePeer;

class LuceneListener
{
    public function onPostSave(ArticleEvent $event)
    {
        $article = $event->getArticle();

          // ...
      }
}
namespace AFUPListener;

// ...
class LuceneListener
{
    public function onPostSave(ArticleEvent $event)
    {
        $article = $event->getArticle();
        $index = ArticlePeer::getLuceneIndex();

        // remove existing entries
        foreach ($index->find('pk:'.$article->getId()) as $hit) {
            $index->delete($hit->id);
        }

        $doc = new Document();
        $doc->addField(Field::Keyword('pk', $article->getId()));
        $doc->addField(Field::UnStored('title', $article->getTitle()));
        $doc->addField(Field::UnStored('content', $article->getContent()));

        $index->addDocument($doc);
        $index->commit();
    }
}
Enregistrer les
    écouteurs
use   SymfonyComponentEventDispatcherEventDispatcher;
use   AFUPListenerArticleListener;
use   AFUPListenerLuceneListener;
use   AFUPModelArticle;

// Déclaration des écouteurs
$listener1 = array(new ArticleListener(), 'onPreSave');
$listener2 = array(new LuceneListener(), 'onPostSave');

// Enregistrement des écouteurs
$dispatcher = new EventDispatcher();
$dispatcher->addListener('article.pre_save', $listener1);
$dispatcher->addListener('article.post_save', $listener2);
$article = new Article();

$article->setDispatcher($dispatcher);

$article->setTitle('AFUP Design Patterns');

$article->setMarkdownContent(
    'Some **markdown** content'
);

$article->save();
Dependency Injection
Mauvaise
Conception
Initiale
class Mailer
{
    public function send(Message $message)
    {
        try {
             $transport = new SMTPTransport(
                 'smtp.foo.com', 1234, 'mailer', 'p$wD^'
             );
             return $transport->send($message);
        } catch (TransportException $e) {
             $logger = Logger::getInstance();
             $logger->log('Unable to send message to...');
             $logger->logException($e);
             throw $e;
        }
    }
}
$message = new Message();
$message->setFrom('me@example.com');
$message->setTo('you@example.com');
$message->setSubject('Bonjour ...');
$message->setBody('Hello ...');

$mailer = new Mailer();
$mailer->send($message);
Ca fonctionne !
Oui mais ?!!!
$transport = new SMTPTransport(
    'smtp.foo.com',
     1234,
     'mailer',
     'p$wD^'
);
Je veux utiliser
un transport
différent…
Je veux configurer
le SMTP en dev et
en prod…
$logger = Logger::getInstance();
$logger->log('Unable to...');
$logger->logException($e);
Si le logger
n’existe pas ?
Si je veux changer
la configuration
du logger?
Je veux tester mon
code avec PHPUnit
et je n’y arrive
pas…
La Solution?
Injecter ses
dépendances au
Mailer
What ???
Injection par
les propriétés
class Mailer
{
    public $transport;

    public function send(Message $message)
    {
        try {
            $this->transport->send($message);
        } catch (TransportException $e) {
            // ...
        }
    }
}
$message = Message();
$message->setFrom('me@example.com');
$message->setTo('you@example.com');
$message->setSubject('Bonjour ...');
$message->setBody('Hello ...');

$transport = new SMTPTransport('...');

$mailer = new Mailer();
$mailer->transport = $transport;
$mailer->send($message);
Injection par
constructeur
class Mailer
{
    private $transport;

    function __construct(Transport $t)
    {
        $this->transport = $t;
    }
}
$message = Message();
$message->setFrom('me@example.com');
// ...

$transport = new SMTPTransport('...');

$mailer = new Mailer($transport);
$mailer->send($message);
Injection par
un mutateur
class Mailer
{
    private $logger;

    function setLogger(Logger $logger)
    {
        $this->logger = $logger;
    }
}
class Mailer
{
    // ...
    public function send(Message $message)
    {
        try {
             $this->transport->send($message);
        } catch (TransportException $e) {
             if (null !== $this->logger) {
                 $this->logger->log('...');
                 $this->logger->logException($e);
                 throw $e;
             }
        }
    }
}
$message = Message();
// ...

$logger = new FileLogger('/to/dev.log');
$transport = new SMTPTransport('...');

$mailer = new Mailer($transport);
$mailer->setLogger($logger);
$mailer->send($message);
Découplage
avec les
interfaces
class Mailer
{
    function __construct(TransportInterface $t)
    {
        $this->transport = $t;
    }

    function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}
class SMTPTransport implements TransportInterface
{
}

class MailTransport implements TransportInterface
{
}

class NullTransport implements TransportInterface
{
}
Bénéfices vs
Pertes ?!
Configurabilité
   Modularité
      Testabilité
Construction
   un peu plus
      Complexe
Inversion de Contrôle
# composer.json
{
    "require": {
        "pimple/pimple": "1.0.*"
    }
}
Global Configuration
    + Lazy Services
        = Container
Paramètres
Globaux de
Configuration
$pimple = new Pimple();

$pimple['logger.file'] = '/path/to/dev.log';
$pimple['logger.severity'] = 200;

$pimple['transport.smtp.host'] =   'smtp.foo.com';
$pimple['transport.smtp.port'] =   1234;
$pimple['transport.smtp.user'] =   'mailer';
$pimple['transport.smtp.passwd']   = '^p4$$W0rD*';
Enregistrer
des services
$pimple['logger'] = $pimple->share(function ($c) {

      if (!is_writable($c['logger.file'])) {
          throw new Exception('...');
      }

      $logger = new Logger($c['logger.file']);

      if (isset($c['logger.severity'])) {
          $logger->setSeverity($c['logger.severity']);
      }

      return $logger;
});
$pimple['mailer.transport'] = $pimple
->share(function ($c) {

      return new SMTPTransport(
          $c['transport.smtp.host'],
          $c['transport.smtp.port'],
          $c['transport.smtp.user'],
          $c['transport.smtp.passwd']
      );
});
$pimple['mailer'] = $pimple->share(function ($c) {

      $mailer = new Mailer($c['mailer.transport']);

      if (isset($c['logger'])) {
          $mailer->setLogger($c['logger']);
      }

      return $mailer;
});
Initialisation des
services à la
demande
$pimple = new Pimple();
$pimple['logger.file'] = '/path/to/dev.log';
$pimple['logger.severity'] = 200;
// ...

$message = Message();
$message->setFrom('me@example.com');
// ...

// Création à la demande du mailer
$pimple['mailer']->send($message);
Design Patterns avec PHP 5.3, Symfony et Pimple

More Related Content

What's hot

Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
Bill Chang
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
Fabien Potencier
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
Hugo Hamon
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
Fabien Potencier
 

What's hot (20)

Lithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate FrameworksLithium: The Framework for People Who Hate Frameworks
Lithium: The Framework for People Who Hate Frameworks
 
Doctrine fixtures
Doctrine fixturesDoctrine fixtures
Doctrine fixtures
 
Dependency Injection IPC 201
Dependency Injection IPC 201Dependency Injection IPC 201
Dependency Injection IPC 201
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you needDutch PHP Conference - PHPSpec 2 - The only Design Tool you need
Dutch PHP Conference - PHPSpec 2 - The only Design Tool you need
 
The Origin of Lithium
The Origin of LithiumThe Origin of Lithium
The Origin of Lithium
 
Command Bus To Awesome Town
Command Bus To Awesome TownCommand Bus To Awesome Town
Command Bus To Awesome Town
 
The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016The IoC Hydra - Dutch PHP Conference 2016
The IoC Hydra - Dutch PHP Conference 2016
 
Speed up your developments with Symfony2
Speed up your developments with Symfony2Speed up your developments with Symfony2
Speed up your developments with Symfony2
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo EditionLithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
 
Building Lithium Apps
Building Lithium AppsBuilding Lithium Apps
Building Lithium Apps
 
The State of Lithium
The State of LithiumThe State of Lithium
The State of Lithium
 
Design how your objects talk through mocking
Design how your objects talk through mockingDesign how your objects talk through mocking
Design how your objects talk through mocking
 
News of the Symfony2 World
News of the Symfony2 WorldNews of the Symfony2 World
News of the Symfony2 World
 
Electrify your code with PHP Generators
Electrify your code with PHP GeneratorsElectrify your code with PHP Generators
Electrify your code with PHP Generators
 
Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010Symfony2 - WebExpo 2010
Symfony2 - WebExpo 2010
 
Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12Symfony components in the wild, PHPNW12
Symfony components in the wild, PHPNW12
 
Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)Doctrine MongoDB ODM (PDXPHP)
Doctrine MongoDB ODM (PDXPHP)
 
Symfony War Stories
Symfony War StoriesSymfony War Stories
Symfony War Stories
 
Decoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDDDecoupling the Ulabox.com monolith. From CRUD to DDD
Decoupling the Ulabox.com monolith. From CRUD to DDD
 

Similar to Design Patterns avec PHP 5.3, Symfony et Pimple

SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
jsmith92
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
smueller_sandsmedia
 

Similar to Design Patterns avec PHP 5.3, Symfony et Pimple (20)

How Kris Writes Symfony Apps
How Kris Writes Symfony AppsHow Kris Writes Symfony Apps
How Kris Writes Symfony Apps
 
PhpUnit - The most unknown Parts
PhpUnit - The most unknown PartsPhpUnit - The most unknown Parts
PhpUnit - The most unknown Parts
 
Unittests für Dummies
Unittests für DummiesUnittests für Dummies
Unittests für Dummies
 
Adding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy ApplicationsAdding Dependency Injection to Legacy Applications
Adding Dependency Injection to Legacy Applications
 
Extbase and Beyond
Extbase and BeyondExtbase and Beyond
Extbase and Beyond
 
Mocking Demystified
Mocking DemystifiedMocking Demystified
Mocking Demystified
 
Advanced php testing in action
Advanced php testing in actionAdvanced php testing in action
Advanced php testing in action
 
SPL: The Missing Link in Development
SPL: The Missing Link in DevelopmentSPL: The Missing Link in Development
SPL: The Missing Link in Development
 
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for PerformanceMeet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
Meet Magento Sweden - Magento 2 Layout and Code Compilation for Performance
 
PHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolvePHPCon 2016: PHP7 by Witek Adamus / XSolve
PHPCon 2016: PHP7 by Witek Adamus / XSolve
 
Php unit the-mostunknownparts
Php unit the-mostunknownpartsPhp unit the-mostunknownparts
Php unit the-mostunknownparts
 
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnitinternational PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
international PHP2011_Bastian Feder_The most unknown Parts of PHPUnit
 
A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014A Series of Fortunate Events - Symfony Camp Sweden 2014
A Series of Fortunate Events - Symfony Camp Sweden 2014
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
A Series of Fortunate Events - Drupalcon Europe, Amsterdam 2014
 
Symfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technologySymfony2 Building on Alpha / Beta technology
Symfony2 Building on Alpha / Beta technology
 
Oops in php
Oops in phpOops in php
Oops in php
 
The IoC Hydra
The IoC HydraThe IoC Hydra
The IoC Hydra
 
Doctrine For Beginners
Doctrine For BeginnersDoctrine For Beginners
Doctrine For Beginners
 
Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4Can't Miss Features of PHP 5.3 and 5.4
Can't Miss Features of PHP 5.3 and 5.4
 

More from Hugo Hamon

Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
Hugo Hamon
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Hugo Hamon
 

More from Hugo Hamon (11)

Monitor the quality of your Symfony projects
Monitor the quality of your Symfony projectsMonitor the quality of your Symfony projects
Monitor the quality of your Symfony projects
 
Intégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CIIntégration Continue PHP avec Jenkins CI
Intégration Continue PHP avec Jenkins CI
 
Symfony2 - extending the console component
Symfony2 - extending the console componentSymfony2 - extending the console component
Symfony2 - extending the console component
 
Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)Développeurs, cachez-moi ça ! (Paris Web 2011)
Développeurs, cachez-moi ça ! (Paris Web 2011)
 
Symfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 PerformantSymfony2 - Un Framework PHP 5 Performant
Symfony2 - Un Framework PHP 5 Performant
 
Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2Build powerfull and smart web applications with Symfony2
Build powerfull and smart web applications with Symfony2
 
Intégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec JenkinsIntégration continue des projets PHP avec Jenkins
Intégration continue des projets PHP avec Jenkins
 
Symfony2 en pièces détachées
Symfony2 en pièces détachéesSymfony2 en pièces détachées
Symfony2 en pièces détachées
 
Mieux Développer en PHP avec Symfony
Mieux Développer en PHP avec SymfonyMieux Développer en PHP avec Symfony
Mieux Développer en PHP avec Symfony
 
Introduction à Symfony2
Introduction à Symfony2Introduction à Symfony2
Introduction à Symfony2
 
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend FrameworkExposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
Exposer des services web SOAP et REST avec symfony 1.4 et Zend Framework
 

Recently uploaded

EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
Earley Information Science
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
giselly40
 

Recently uploaded (20)

How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
presentation ICT roal in 21st century education
presentation ICT roal in 21st century educationpresentation ICT roal in 21st century education
presentation ICT roal in 21st century education
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Evaluating the top large language models.pdf
Evaluating the top large language models.pdfEvaluating the top large language models.pdf
Evaluating the top large language models.pdf
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 

Design Patterns avec PHP 5.3, Symfony et Pimple