DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
View Events Video Library
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • The Role of JavaScript in Front-End and Back-End Development
  • A Multilingual Prestashop Online Store Using ChatGPT
  • A Step-By-Step Guide: How To Install a Laravel Script
  • PHP or ASP.NET: Which Powerhouse Platform Prevails for Your Next Project?

Trending

  • Information Security: AI Security Within the IoT Industry
  • How To Validate Archives and Identify Invalid Documents in Java
  • Reflections From a DBA
  • AWS Amplify: A Comprehensive Guide
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Patterns: Mapper

Practical PHP Patterns: Mapper

Giorgio Sironi user avatar by
Giorgio Sironi
·
Sep. 13, 10 · Interview
Like (0)
Save
Tweet
Share
4.38K Views

Join the DZone community and get the full member experience.

Join For Free

The Mapper pattern is used to establish a communication between two subsystems, when the integration must be managed in a way to avoid creating mutual dependencies or even one-way dependencies between them.

The classic example of this pattern is its specialization for data storage, the Data Mapper, which as you can see from the relative article translates data between an object graph and an external storage such as a relational database (most advanced ORMs like Doctrine 2 are Data Mappers), but also a document-oriented database or any other kind of persistent storage.

The Mapper component is naturally dependent on both the subsystems it connect, but they are not aware at all of its existence. No additional hard dependencies are introduced from the subsystems towards other components.

Following our example, Doctrine 2 borrows the Hibernate's approach to mapping: it parses annotations or unobtrusive XML files for specifying metadata on the object-oriented side, and uses a wrapped version of PDO (with ordinary database drivers) on the database side. Neither the database tables are aware of the existence of an object model, nor the objects are ideally aware of them being persisted into a tabular form.

Client code

The main issue in wiriting a Mapper, in all its specializations, is how to invoke it, since the connected subsystems do not know anything about it, nor they can instance it without a dependency being created.

The most common solution is to use an higher-level layer that drives the three components at the same time. In PHP applications, this is usually a controller layer, which by default starts a transaction and commit it following the lifecycle of the served HTTP request. The domain objects are then passed to the Data Mapper's Facade or they depend on a set of Repository interfaces implemented with the aid of the Data Mapper.

Another possible solution is to implement an Observer pattern, so that interfaces or abstractions in the two subsystems break the dependency. The Mapper implementation classes would realize these interfaces, but there is a trade-off produced by the introduction of interfaces in the subsystems.

Mapper vs. Gateway

In comparison, a Gateway is simpler to implement than a Mapper, although your mileage may vary depending on the domain and your requirements.

Basically, a Mapper is more complex but by definition it has the benefit that neither of the two components depend on it. Thus the Mapper is even more decoupled than one of the two subsystems dependent on an interface or abstraction of a Gateway: in fact, you can simply throw it out the Mapper and the two subsystems will work as long as they can to fulfill their own responsibilities. Whereas, you can't remove a Gateway from an application without specifying an alternate implementation.

This pattern is also different from a Mediator: no one of the objects at the same or at a lower layer of the Mapper is aware of it.

Example

The code sample is a simple Data Mapper that shuffles data between database and Twitter, just to shake the notion that all Data Mappers are ORMs.

The code presented here is only a one-way implementation, since a bidirectional one would involve authentication and would increase too much the size of this article.
The first side of the Mapper is a domain model built over the database (not represented here). The second side is Twitter's own web services instead, which we can be sure does not depend on our little in-memory database.

<?php
class TwitterMapper
{
    private $connection;

    /**
     * The Mapper composes one side of the computation (the database)
     * in the form of its Facade (the connection).
     * The other side is Twitter's web service, so it isn't injected
     * for simplicity.
     */
    public function __construct(PDO $connection)
    {
        $this->connection = $connection;
    }

    /**
     * the only functionality I need from the feed
     */
    public function synchronizeLastTweets(array $usernames)
    {
        foreach ($usernames as $username) {
            $endPoint = "http://twitter.com/statuses/user_timeline/{$username}.xml?count=1";
            $buffer = file_get_contents($endPoint);
            $xml = new SimpleXMLElement($buffer);
            $this->_addTweet($xml->id, $username, $xml->status->text);
        }
    }

    public function _addTweet($id, $username, $text)
    {
        $stmt = $this->connection->prepare('INSERT INTO tweets (id, username, text) VALUES (:id, :username, :text)');
        $stmt->bindValue(':id', $id, PDO::PARAM_STR);
        $stmt->bindValue(':username', $username, PDO::PARAM_STR);
        $stmt->bindValue(':text', $text, PDO::PARAM_STR);
        return $stmt->execute();
    }
}

$pdo = new PDO('sqlite::memory:');
$pdo->exec('CREATE TABLE tweets (id INT NOT NULL, username VARCHAR(255) NOT NULL, text VARCHAR(255) NOT NULL, PRIMARY KEY(id))');

$mapper = new TwitterMapper($pdo);
// higher-level layer
$mapper->synchronizeLastTweets(array('giorgiosironi')); 
PHP

Opinions expressed by DZone contributors are their own.

Related

  • The Role of JavaScript in Front-End and Back-End Development
  • A Multilingual Prestashop Online Store Using ChatGPT
  • A Step-By-Step Guide: How To Install a Laravel Script
  • PHP or ASP.NET: Which Powerhouse Platform Prevails for Your Next Project?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends: