SkillAgentSearch skills...

Maphper

Maphper - A php ORM using the Data Mapper pattern

Install / Use

/learn @Level-2/Maphper
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Maphper

Maphper - A php ORM using the Data Mapper pattern

A work in progress!

Scrutinizer-CI

Features:

  1. Creates database tables on the fly

  2. Currently supports database tables but will support XML files, web services even twitter feeds as Data Sources

  3. Supports relations between any two data sources

  4. Composite primary keys

Maphper takes a simplistic and minimalist approach to data mapping and aims to provide the end user with an intuitive and easy to use API.

The main philosophy of Maphper is that the programmer should deal with sets of data and then be able to manipulate the set and extract other data from it.

Basic Usage

This sets up a Data Mapper that maps to the 'blog' table in a MySQL database. Each mapper has a data source. This source could be anything, a database table, an XML file, a folder full of XML files, a CSV, a Twitter feed, a web service, or anything.

The aim is to give the developer a consistent and simple API which is shared between any of the data sources.

It's then possible to treat the $blogs object like an array.

To set up a Maphper object using a Database Table as its Data Source, first create a standard PDO instance:

$pdo = new PDO('mysql:dbname=maphpertest;host=127.0.0.1', 'username', 'password');

Then create an instance of \Maphper\DataSource\Database passing it the PDO instance, name of the table and primary key:

$blogSource = new \Maphper\DataSource\Database($pdo, 'blog', 'id');

Finally create an instance of \Maphper\Maphper and pass it the data source:

$blogs = new \Maphper\Maphper($blogSource);

You can loop through all the blogs using:

// Equivalent to SELECT * FROM blogs
foreach ($blogs as $blog) {
  echo $blog->title . '<br />';
}

Any fields from the database table (or xml file, web service, etc) will be available in the $blog object

Alternatively you can find a specific blog using the ID

//Equivalent to SELECT * FROM blogs WHERE id = 142
echo $blogs[142]->title;

Which will find a blog with the id of 142 and display the title.

Filters

Maphper supports filtering the data:

//find blogs that were posted on a specific date
//Equivalent to SELECT * FROM blogs WHERE date = '2015-04-09'
$filteredBlogs = $blogs->filter(['date' => '2014-04-09']);

//this will only retrieve blogs that were matched by the filter
foreach ($filteredBlogs as $blog) {
	echo $blog->title;
}

Filters can be extended and chained together:

//find blogs that were posted with the title "My Blog" by the author with the id of 7
//Equivalent to SELECT * FROM blogs WHERE title = 'My Blog' AND authorId = 7 
$filteredBlogs = $blogs->filter(['title' => 'My Blog'])->filter(['authorId' => 7]);

//this will only retrieve blogs that were matched by both filters
foreach ($filteredBlogs as $blog) {
	echo $blog->title;
}

As well as filtering there are both sort() and limit() methods which can all be chained:

foreach ($blogs->filter(['date' => '2014-04-09']) as $blog) {
  echo $blog->title;
}

To find the latest 5 blogs you could use:

//Equivalent to SELECT * FROM blogs LIMIT 5 ORDER BY date DESC
foreach ($blogs->limit(5)->sort('date desc') as $blog) {
  echo $blog->title;
}

Like any array, you can count the total number of blogs using:

//Equivalent to SELECT count(*) FROM lblogs
echo 'Total number of blogs is ' . count($blogs);

This will count the total number of blogs in the table. You can also count filtered results:

//Count the number of blogs in category 3
//Equivalent to SELECT count(*) FROM blogs WHERE categoryId =  3
echo count($blogs->filter(['categoryId' => 3]);

Saving Data

To save an object back into the data mapper, simply create an instance of stdClass:

$pdo = new PDO('mysql:dbname=maphpertest;host=127.0.0.1', 'username', 'password');
$blogSource = new \Maphper\DataSource\Database($pdo, 'blog', 'id');
$blogs = new \Maphper\Maphper($blogSource);


$blog = new stdClass;

$blog->title = 'My Blog Title';
$blog->content = 'This is my first blog entry';

//Store the blog using the next available ID
$blogs[] = $blog;

echo 'The new blog ID is :' . $blog->id;

Alternatively, you can write a record to a specific ID by specifying the index:

$blog = new stdClass;

$blog->title = 'My Blog Title';
$blog->content = 'This is my first blog entry';

//Store the blog with the primary key of 7
$blogs[7] = $blog;

Note: The behaviour of this is identical to setting the id property on the $blog object directly:


$blog = new stdClass;

$blog->id = 7;
$blog->title = 'My Blog Title';
$blog->content = 'This is my first blog entry';

//Store the blog with the primary key of 7
$blogs[] = $blog;

Relationships

If there was an author table which stored information about blog authors, it could be set up in a similar way:

$authorSource = new \Maphper\DataSource\Database($pdo, 'author', 'id');
$authors = new \Maphper\Maphper($authorSource);

This could be used similarly:

$author = $authors[123];
echo $author->name;

Once both the blogs and authors mappers have been defined, you can create a relationship between them.

This is a one-to-one relationship (one blog has one author) and can be achieved using the addRelation method on the blog mapper:

//Create a one-to-one relationship between blogs and authors (a blog can only have one author)
$relation = new \Maphper\Relation\One($authors, 'authorId', 'id');
$blogs->addRelation('author', $relation);

Using an instance of \Maphper\Relation\One tells Maphper that it's a one-to-one relationship

The first parameter, $authors tells Maphper that the relationship is to the $authors mapper (in this case, the author database table, although you can define relationships between different data sources)

authorId is the field in the blog table that's being joined from

id is the field in the author table that's being joined to

After the relation is constructed it can be added to the blog mapper using:

$blogs->addRelation('author', $relation);

The first parameter (here: 'author') is the name of the property the related data will be available under. So any object retrieved from the $blogs mapper will now have an 'author' property that contains the author of the blog and can be used like this:

foreach ($blogs as $blog) {
  echo $blog->title . '<br />';
  echo $blog->author->name . '<br />';
}

Similarly, you can define the inverse relation between authors and blogs. This is a one-to-many relationship because an author can post more than one blog.

//Create a one-to-many relationship between blogs and authors (an author can have multiple blog entries)
//Joining from the 'id' field in the authors mapper to the 'authorId' field in the blogs mapper
$relation = new \Maphper\Relation\Many($blogs, 'id', 'authorId');
$authors->addRelation('blogs', $relation);

This is creating a One:Many relationship between the $authors and $blogs mappers using the id field in the $authors mapper to the authorId field in the $blogs mapper and making a blogs property available for any object returned by the $authors mapper.

//Count all the blogs by the author with id 4
$authors[4]->name . ' has posted ' .  count($authors[4]->blogs)  . ' blogs:<br />';

//Loop through all the blogs created by the author with id 4
foreach ($authors[4]->blogs as $blog) {
    echo $blog->title . '<br />';
}

Saving values with relationships

Once you have created your mappers and defined the relationships between them, you can write data using the relationship. This will automatically set any related fileds behind the scenes.

$authors = new \Maphper\Maphper(new \Maphper\DataSource\Database($pdo, 'author'));
$blogs = new \Maphper\Maphper(new \Maphper\DataSource\Database($pdo, 'blog', 'id'));
$blogs->addRelation('author', new \Maphper\Relation\One($authors, 'authorId', 'id'));


$blog = new stdClass;
$blog->title = 'My First Blog';
$blog->date = new \DateTime();
$blog->author = new stdClass;
$blog->author->name = 'Tom Butler';

$blogs[] = $blog;

This will save both the $blog object into the blog table and the $author object into the author table as well as setting the blog record's authorId column to the id that was generated.

You can also do the same with one-to-many relationships:

$authors = new \Maphper\Maphper(new \Maphper\DataSource\Database($pdo, 'author'));
$blogs = new \Maphper\Maphper(new \Maphper\DataSource\Database($pdo, 'blog', 'id'))

$authors->addRelation('blogs', new \Maphper\Relation\Many($blogs, 'id', 'authorId'));


//Find the author with id 4
$author = $authors[4]; 


$blog = new stdClass;
$blog->title = 'My New Blog';
$blog->date = new \DateTime();

//Add the blog to the author. This will save to the database at the this point, you do not need to explicitly 
//Save the $author object after adding a blog to it.
$author->blogs[] = $blog;

Composite Primary Keys

Maphper allows composite primary keys. For example, if you had a table of products you could use the manufacturer id and manufacturer part number as primary keys (Two manufacuterers may use the same part number)

To do this, define the data source with an array for the primary key:

$pdo = new PDO('mysql:dbname=maphpertest;host=127.0.0.1', 'username', 'password');
$productSource = new \Maphper\DataSource\Database($pdo, 'products', ['manufacturerId', 'partNumber']);
$products = new \Maphper\Maphper($productSource);

Once you have defined the source to use multiple keys, you can treat the $products variable like a two dimensional array:

//Get the prod
View on GitHub
GitHub Stars54
CategoryDevelopment
Updated1y ago
Forks7

Languages

PHP

Security Score

80/100

Audited on Dec 12, 2024

No findings