Skip to content

Commit

Permalink
Add EmailAddress value object
Browse files Browse the repository at this point in the history
Initialization and checks of the Email Address value object.
  • Loading branch information
ocubom committed Sep 16, 2014
1 parent 1cf7b88 commit a2cd96e
Show file tree
Hide file tree
Showing 3 changed files with 255 additions and 3 deletions.
137 changes: 137 additions & 0 deletions src/Address.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
<?php

/*
* This file is part of "Email Address" component.
*
* © Oscar Cubo Medina <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Ocubom\Email;

/**
* Email address value
*
* @author Oscar Cubo Medina <[email protected]>
*
* @property-read string $local The parsed local part
* @property-read string $domain The parsed domain part
* @property-read array $status The diagnoses
*/
class Address
{
/**
* Parsed address components
*
* @var array
*/
private $data;

/**
* Constructor
*
* @param string $address The email address
* @param boolean $checkdns Perform DNS checks (may impact performance)
*/
public function __construct($address, $checkdns = true)
{
$code = is_email($address, $checkdns, true, $parsed);
if (ISEMAIL_THRESHOLD < $code) {
throw new \RuntimeException(sprintf('Invalid email address "%s"', $address), $code);
}

$this->data = array(
// Case on local-part is mandatory but most domains just ignore it
// http://wikipedia.org/wiki/Email_address#Local_part
'local' => $parsed[0],

// Lowercased domain is mandatory
// http://tools.ietf.org/html/rfc1035#section-2.3.1
'domain' => strtolower($parsed[1]),

// Diagnoses
// http://github.com/dominicsayers/isemail/blob/master/is_email.php#L61
'status' => $parsed['status'],
);
}

/**
* Whether or not a property exists.
*
* @param string $name A property to check for.
*
* @return boolean True if the property exists
*/
public function __isset($name)
{
return array_key_exists($name, $this->data);
}

/**
* Returns the specified property value.
*
* @param string $name The property to retrieve.
*
* @return mixed
*/
public function __get($name)
{
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}

// Simulate PHP native behaviour
// http://php.net/manual/en/language.oop5.overloading.php#example-232
trigger_error(sprintf('Undefined property: %s::$%s', get_class($this), $name));

// Previous sentence must abort execution on tests: this will never be called
// @codeCoverageIgnoreStart
return null;
// @codeCoverageIgnoreEnd
}

/**
* Assigns a value to the specified property.
*
* @param string $name The property to assign the value to.
* @param mixed $value The value to set.
*/
final public function __set($name, $value)
{
// Avoid changes
trigger_error(sprintf('Cannot modify read-only class property: %s::$%s', get_class($this), $name, $value));

// Previous sentence must abort execution on tests: this will never be called
// @codeCoverageIgnoreStart
return;
// @codeCoverageIgnoreEnd
}

/**
* Unsets a property.
*
* @param string $name The property to unset.
*/
final public function __unset($name)
{
// Avoid changes
trigger_error(sprintf('Cannot delete read-only class property: %s::$%s', get_class($this), $name));

// Previous sentence must abort execution on tests: this will never be called
// @codeCoverageIgnoreStart
return;
// @codeCoverageIgnoreEnd
}

/**
* Textual representation
*
* @return string
*/
public function __toString()
{
return sprintf('%s@%s', $this->data['local'], $this->data['domain']);
}
}
118 changes: 118 additions & 0 deletions tests/AddressTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

/*
* This file is part of "Email Address" component.
*
* © Oscar Cubo Medina <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Ocubom\Email\Tests;

use Ocubom\Email\Address as EmailAddress;

/**
* Email Address Tests
*
* @author Oscar Cubo Medina <[email protected]>
*/
class AddressTest extends \PHPUnit_Framework_TestCase
{
/**
* Valid address
*/
public function testValidEmailAddress()
{
$obj = new EmailAddress('[email protected]');

// Must have local, domain and status properties
$this->assertTrue(isset($obj->local), 'Email address must have local attribute');
$this->assertTrue(isset($obj->domain), 'Email address must have domain attribute');
$this->assertTrue(isset($obj->status), 'Email address must have status attribute');

// Must return parsed values
$this->assertEquals('JohnDoe', $obj->local);
$this->assertEquals('example.com', $obj->domain);
$this->assertEquals(array(ISEMAIL_DNSWARN_NO_MX_RECORD), $obj->status);

// Must convert into string
$this->assertEquals('[email protected]', (string) $obj, 'Email address must convert to string');
}

/**
* Valid address without DNS check
*/
public function testValidEmailAddressWithoutDNS()
{
$obj = new EmailAddress('[email protected]', false);

// Must have local, domain and status properties
$this->assertTrue(isset($obj->local), 'Email address must have local attribute');
$this->assertTrue(isset($obj->domain), 'Email address must have domain attribute');
$this->assertTrue(isset($obj->status), 'Email address must have status attribute');

// Must return parsed values
$this->assertEquals('JohnDoe', $obj->local);
$this->assertEquals('example.com', $obj->domain);
$this->assertEquals(array(ISEMAIL_VALID), $obj->status);

// Must convert into string
$this->assertEquals('[email protected]', (string) $obj, 'Email address must convert to string');
}

/**
* Invalid address must generate exceptions
*
* @expectedException \RuntimeException
* @expectedExceptionMessage Invalid email address ""
* @expectedExceptionCode 131
*/
public function testInvalidEmailAddress()
{
new EmailAddress('');
}

/**
* Access to undefined properties must generate errors
*
* @expectedException PHPUnit_Framework_Error
* @expectedExceptionMessage Undefined property: Ocubom\Email\Address::$noexists
* @expectedExceptionCode 1024
*/
public function testEmailAddressUndefinedProperties()
{
$obj = new EmailAddress('[email protected]');

echo $obj->noexists;
}

/**
* Test that email address is inmutable
*
* @expectedException PHPUnit_Framework_Error
* @expectedExceptionMessage Cannot modify read-only class property: Ocubom\Email\Address::$local
* @expectedExceptionCode 1024
*/
public function testInmutableEmailAddressHasSetDisabled()
{
$obj = new EmailAddress('[email protected]');

$obj->local = 'doe';
}

/**
* Test that email address is inmutable
*
* @expectedException PHPUnit_Framework_Error
* @expectedExceptionMessage Cannot delete read-only class property: Ocubom\Email\Address::$domain
* @expectedExceptionCode 1024
*/
public function testInmutableEmailAddressHasUnsetDisabled()
{
$obj = new EmailAddress('[email protected]');

unset($obj->domain);
}
}
3 changes: 0 additions & 3 deletions tests/IsEmailTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@

namespace Ocubom\Email\Tests;

use Ocubom\Email\Address as EmailAddress;
use Ocubom\Email\RFC\Diagnose;

/**
* Test email address
*
Expand Down

0 comments on commit a2cd96e

Please sign in to comment.