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
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
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

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Inheritance in PHP: A Simple Guide With Examples
  • The Blue Elephant in the Room: Why PHP Should Not Be Ignored Now or Ever
  • Laravel for Beginners: An Overview of the PHP Framework
  • Is PHP Still the Best Language in 2024?

Trending

  • Intro to RAG: Foundations of Retrieval Augmented Generation, Part 1
  • How Can Developers Drive Innovation by Combining IoT and AI?
  • Customer 360: Fraud Detection in Fintech With PySpark and ML
  • AI-Driven Root Cause Analysis in SRE: Enhancing Incident Resolution
  1. DZone
  2. Coding
  3. Languages
  4. Practical PHP Patterns: Mapper

Practical PHP Patterns: Mapper

By 
Giorgio Sironi user avatar
Giorgio Sironi
·
Sep. 13, 10 · Interview
Likes (0)
Comment
Save
Tweet
Share
5.4K 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

  • Inheritance in PHP: A Simple Guide With Examples
  • The Blue Elephant in the Room: Why PHP Should Not Be Ignored Now or Ever
  • Laravel for Beginners: An Overview of the PHP Framework
  • Is PHP Still the Best Language in 2024?

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • 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:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!