├── .gitignore ├── src └── Ddd │ ├── Time │ ├── .gitignore │ ├── Tests │ │ ├── TestCase.php │ │ ├── Model │ │ │ ├── FixedDateIntervalTest.php │ │ │ ├── DateTest.php │ │ │ ├── DateIntervalTest.php │ │ │ ├── TimePointTest.php │ │ │ ├── FixedDateTest.php │ │ │ ├── DurationTest.php │ │ │ └── TimeIntervalTest.php │ │ ├── Factory │ │ │ ├── TimePointFactoryTest.php │ │ │ ├── DateIntervalFactoryTest.php │ │ │ └── TimeIntervalFactoryTest.php │ │ └── HowTo │ │ │ ├── TimeOfDayTest.php │ │ │ ├── TimeIntervalTest.php │ │ │ ├── DurationTest.php │ │ │ ├── DateIntervalTest.php │ │ │ ├── TimePointTest.php │ │ │ └── DateTest.php │ ├── phpunit.xml.dist │ ├── Factory │ │ ├── DateFactory.php │ │ ├── DurationFactory.php │ │ ├── TimePointFactory.php │ │ ├── DateIntervalFactory.php │ │ └── TimeIntervalFactory.php │ ├── Model │ │ ├── IntervalInterface.php │ │ ├── FixedDate.php │ │ ├── TimeUnit.php │ │ ├── TimeInterval.php │ │ ├── FixedDateInterval.php │ │ ├── TimeOfDay.php │ │ ├── DateInterval.php │ │ ├── Date.php │ │ ├── TimePoint.php │ │ └── Duration.php │ ├── Bridge │ │ └── Doctrine │ │ │ └── Types │ │ │ ├── DateType.php │ │ │ ├── TimePointType.php │ │ │ ├── DateIntervalType.php │ │ │ └── TimeIntervalType.php │ ├── composer.json │ └── README.md │ ├── Calendar │ ├── .gitignore │ ├── Tests │ │ ├── TestCase.php │ │ ├── HowTo │ │ │ ├── DoctorCalendarRepository.php │ │ │ └── CalendarTest.php │ │ └── Model │ │ │ └── CalendarTest.php │ ├── Exception │ │ ├── CalendarExceptionInterface.php │ │ └── CalendarEventException.php │ ├── Service │ │ ├── EventProviderInterface.php │ │ ├── CalendarPersisterInterface.php │ │ ├── EventPersisterInterface.php │ │ └── CalendarLoaderInterface.php │ ├── Model │ │ ├── NamedEventInterface.php │ │ ├── SendableEventInterface.php │ │ ├── EventInterface.php │ │ ├── Event.php │ │ ├── Strategy │ │ │ ├── NoOverlapStrategy.php │ │ │ ├── FrozenStrategy.php │ │ │ ├── StrategyInterface.php │ │ │ ├── BaseStrategy.php │ │ │ └── PersistenceStrategy.php │ │ ├── NamedEvent.php │ │ ├── SendableEvent.php │ │ ├── CalendarInterface.php │ │ └── Calendar.php │ ├── README.md │ ├── phpunit.xml.dist │ ├── composer.json │ └── Infra │ │ └── EventProvider.php │ ├── Mail │ ├── Model │ │ ├── TextMail.php │ │ ├── Contact.php │ │ └── Mail.php │ ├── Service │ │ └── MailerInterface.php │ ├── Exception │ │ ├── MailNotComposedException.php │ │ └── MailWithoutRecipientException.php │ ├── Infra │ │ └── Mailer │ │ │ ├── NullMailer.php │ │ │ ├── SwiftMailer.php │ │ │ └── AmazonSesMailer.php │ ├── composer.json │ ├── Tests │ │ └── Acceptance │ │ │ ├── MailBuilderTest.php │ │ │ ├── BasicMailTest.php │ │ │ └── TextMailTest.php │ ├── MailBuilder.php │ └── README.md │ └── Slug │ ├── Tests │ ├── Resources │ │ └── db.sqlite │ ├── TestDatabase.php │ ├── Fixtures │ │ ├── InMemoryArticle.php │ │ └── DoctrineArticle.php │ ├── AcceptanceDataProvider.php │ └── AcceptanceTest.php │ ├── Model │ └── SluggableInterface.php │ ├── Infra │ ├── Transliterator │ │ ├── PassthruTransliterator.php │ │ ├── LatinTransliterator.php │ │ └── TransliteratorCollection.php │ └── SlugGenerator │ │ ├── PassthruSlugGenerator.php │ │ └── DefaultSlugGenerator.php │ ├── Service │ ├── SlugGeneratorInterface.php │ └── TransliteratorInterface.php │ ├── composer.json │ └── README.md ├── scripts └── do-split.sh ├── README.md ├── phpunit.xml.dist └── composer.json /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | composer.lock 3 | -------------------------------------------------------------------------------- /src/Ddd/Time/.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | *.swp 3 | vendor 4 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | *.swp 3 | vendor 4 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Model/TextMail.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | interface CalendarExceptionInterface 9 | { 10 | function getMessage(); 11 | } 12 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Service/EventProviderInterface.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Service/CalendarPersisterInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tests 7 | 8 | 9 | Tests/HowTo 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Tests 7 | 8 | 9 | Tests/HowTo 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Service/EventPersisterInterface.php: -------------------------------------------------------------------------------- 1 | sent = $sent; 15 | } 16 | 17 | public function send(Mail $mail) 18 | { 19 | return $this->sent ? array() : $mail->getRecipients(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Service/CalendarLoaderInterface.php: -------------------------------------------------------------------------------- 1 | format('Y'), 20 | $dateTime->format('m'), 21 | $dateTime->format('d') 22 | ); 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Model/SluggableInterface.php: -------------------------------------------------------------------------------- 1 | 11 | * @author Jean-François Simon 12 | */ 13 | interface SluggableInterface 14 | { 15 | /** 16 | * Slugifies entity using given slugifier. 17 | * 18 | * @param SlugGeneratorInterface $slugifier 19 | */ 20 | public function slugify(SlugGeneratorInterface $slugifier); 21 | } 22 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Infra/Transliterator/PassthruTransliterator.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class PassthruTransliterator implements TransliteratorInterface 11 | { 12 | /** 13 | * {@inheritdoc} 14 | */ 15 | public function transliterate($string) 16 | { 17 | return $string; 18 | } 19 | 20 | public function getName() 21 | { 22 | return 'passthru'; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Ddd/Time/Factory/DurationFactory.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class PassthruSlugGenerator implements SlugGeneratorInterface 13 | { 14 | /** 15 | * {@inheritdoc} 16 | */ 17 | public function slugify(array $fieldValues, array $options = array()) 18 | { 19 | return implode('', $fieldValues); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Ddd/Mail/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ddd/mail", 3 | "type": "library", 4 | "description": "", 5 | "keywords": ["mail","ddd"], 6 | "homepage": "https://github.com/ddd-php/Mail", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Joseph ROUFF", 11 | "email": "rouffj@gmail.com", 12 | "homepage": "http://josephrouff.com" 13 | } 14 | ], 15 | "require": { 16 | "php": ">=5.3.0" 17 | }, 18 | "autoload": { 19 | "psr-0": { "Ddd\\Mail": "" } 20 | }, 21 | "target-dir": "Ddd/Mail" 22 | } 23 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Model/Contact.php: -------------------------------------------------------------------------------- 1 | email = $email; 13 | $this->name = $name; 14 | } 15 | 16 | public function getEmail() 17 | { 18 | return $this->email; 19 | } 20 | 21 | public function getName() 22 | { 23 | return $this->name; 24 | } 25 | 26 | public function toString() 27 | { 28 | return sprintf("%s <%s>", $this->name, $this->email); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Service/SlugGeneratorInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @author Jean-François Simon 10 | */ 11 | interface SlugGeneratorInterface 12 | { 13 | /** 14 | * Slugifies an array of string values. 15 | * 16 | * @param array $fieldValues 17 | * @param array $options See implementations for available options 18 | * 19 | * @return string 20 | */ 21 | public function slugify(array $fieldValues, array $options = array()); 22 | } 23 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Service/TransliteratorInterface.php: -------------------------------------------------------------------------------- 1 | 9 | * @author Jean-François Simon 10 | */ 11 | interface TransliteratorInterface 12 | { 13 | /** 14 | * Transliterates given string to ascii. 15 | * 16 | * @param string $string 17 | * 18 | * @return string 19 | */ 20 | public function transliterate($string); 21 | 22 | /** 23 | * Name of the transliterator 24 | * 25 | * @return string 26 | */ 27 | public function getName(); 28 | } 29 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/IntervalInterface.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | interface IntervalInterface 9 | { 10 | public function getBegin(); 11 | public function getEnd(); 12 | public function isBefore(IntervalInterface $interval); 13 | public function isAfter(IntervalInterface $interval); 14 | public function isDuring(IntervalInterface $interval); 15 | public function isInclude(IntervalInterface $interval); 16 | public function isPartiallyBefore(IntervalInterface $interval); 17 | public function isPartiallyAfter(IntervalInterface $interval); 18 | } 19 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Event.php: -------------------------------------------------------------------------------- 1 | interval = $interval; 14 | } 15 | 16 | public function getInterval() 17 | { 18 | return $this->interval; 19 | } 20 | 21 | public function isEquals(EventInterface $event) 22 | { 23 | return $this->interval->getBegin()->isEquals($event->getInterval()->getBegin()) 24 | && $this->interval->getEnd()->isEquals($event->getInterval()->getEnd()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Tests/TestDatabase.php: -------------------------------------------------------------------------------- 1 | databasePath = __DIR__.'/Resources/db.sqlite'; 13 | $this->backupPath = __DIR__.'/Resources/db.backup'; 14 | } 15 | 16 | public static function backup() 17 | { 18 | $database = new self(); 19 | copy($database->databasePath, $database->backupPath); 20 | } 21 | 22 | public static function restore() 23 | { 24 | $database = new self(); 25 | rename($database->backupPath, $database->databasePath); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Ddd/Time/Bridge/Doctrine/Types/DateType.php: -------------------------------------------------------------------------------- 1 | toDateTime()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Tests/Fixtures/InMemoryArticle.php: -------------------------------------------------------------------------------- 1 | slug = $slugifier->slugify(array($this->title)); 16 | } 17 | 18 | public function setTitle($title) 19 | { 20 | $this->title = $title; 21 | } 22 | 23 | public function getTitle() 24 | { 25 | return $this->title; 26 | } 27 | 28 | public function getSlug() 29 | { 30 | return $this->slug; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Ddd/Slug/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ddd/slug", 3 | "type": "library", 4 | "description": "", 5 | "keywords": ["slug", "ddd"], 6 | "homepage": "https://github.com/ddd-php/Slug", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Joseph ROUFF", 11 | "email": "rouffj@gmail.com", 12 | "homepage": "http://josephrouff.com" 13 | }, 14 | { 15 | "name": "Jean-François Simon", 16 | "email": "contact@jfsimon.fr", 17 | "homepage": "http://www.jfsimon.fr" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.3.0", 22 | "ext-iconv": "*" 23 | }, 24 | "autoload": { 25 | "psr-0": { "Ddd\\Slug": "" } 26 | }, 27 | "target-dir": "Ddd/Slug" 28 | } 29 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ddd/calendar", 3 | "type": "library", 4 | "description": "", 5 | "keywords": ["time","calendar"], 6 | "homepage": "https://github.com/ddd-php/Calendar", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Joseph ROUFF", 11 | "email": "rouffj@gmail.com", 12 | "homepage": "http://josephrouff.com" 13 | }, 14 | { 15 | "name": "Jean-François Simon", 16 | "email": "contact@jfsimon.fr", 17 | "homepage": "http://www.jfsimon.fr" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.3.0", 22 | "ddd/time": "*" 23 | }, 24 | "autoload": { 25 | "psr-0": { "Ddd\\Calendar": "" } 26 | }, 27 | "target-dir": "Ddd/Calendar" 28 | } 29 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Strategy/NoOverlapStrategy.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class NoOverlapStrategy extends BaseStrategy 15 | { 16 | /** 17 | * {@inheritdoc} 18 | */ 19 | public function add(EventInterface $newEvent, array $events) 20 | { 21 | foreach ($events as $event) { 22 | if ($newEvent->getInterval()->isDuring($event->getInterval())) { 23 | throw CalendarEventException::eventOverlap($newEvent); 24 | } 25 | } 26 | 27 | return parent::add($newEvent, $events); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Infra/EventProvider.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | class EventProvider implements EventProviderInterface 9 | { 10 | /** 11 | * @var string 12 | */ 13 | private $name; 14 | 15 | /** 16 | * @var array 17 | */ 18 | private $events; 19 | 20 | /** 21 | * @param string $name 22 | * @param array $events 23 | */ 24 | public function __construct($name, array $events) 25 | { 26 | $this->name = $name; 27 | $this->events = $events; 28 | } 29 | 30 | /** 31 | * @return array 32 | */ 33 | public function getEvents() 34 | { 35 | return $this->events; 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getName() 42 | { 43 | return $this->name; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Ddd/Time/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ddd/time", 3 | "type": "library", 4 | "description": "", 5 | "keywords": ["time","money"], 6 | "homepage": "https://github.com/ddd-php/Time", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Joseph ROUFF", 11 | "email": "rouffj@gmail.com", 12 | "homepage": "http://josephrouff.com" 13 | }, 14 | { 15 | "name": "Jean-François Simon", 16 | "email": "contact@jfsimon.fr", 17 | "homepage": "http://www.jfsimon.fr" 18 | }, 19 | { 20 | "name": "Julien GALENSKI", 21 | "email": "julien.galenski@gmail.com", 22 | "homepage": "http://www.jgalenski.fr" 23 | } 24 | ], 25 | "require": { 26 | "php": ">=5.3.0" 27 | }, 28 | "autoload": { 29 | "psr-0": { "Ddd\\Time": "" } 30 | }, 31 | "target-dir": "Ddd/Time" 32 | } 33 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Tests/AcceptanceDataProvider.php: -------------------------------------------------------------------------------- 1 | assertTrue($interval->isInclude(DateIntervalFactory::create('2013-01-13', '2013-01-14'))); 18 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-10-13', '2013-10-15'))); 19 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-05-14', '2013-05-15'))); 20 | $this->assertTrue($interval->isInclude(TimeIntervalFactory::create('2013-01-13 01:00', '2013-01-14 18:30'))); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | ./src/Ddd/*/Tests/* 17 | 18 | 19 | ./src/Ddd/*/Tests/HowTo 20 | 21 | 22 | 23 | 24 | ./src/Ddd 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/DateTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(true, $date->isAfter(new Date(2011, 11, 25))); 14 | $this->assertEquals(true, $date->isAfter(new Date(2012, 10, 1))); 15 | $this->assertEquals(true, $date->isAfter(new Date(2012, 11, 1))); 16 | 17 | $this->assertEquals(false, $date->isAfter(new Date(2012, 11, 2))); 18 | $this->assertEquals(false, $date->isAfter(new Date(2012, 11, 5))); 19 | $this->assertEquals(false, $date->isAfter(new Date(2012, 12, 5))); 20 | } 21 | 22 | public function testToDateTime() 23 | { 24 | $date = new Date(2013, 1, 1); 25 | 26 | $this->assertEquals(new \DateTime('2013-01-01 00:00:00'), $date->toDateTime()); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Factory/TimePointFactoryTest.php: -------------------------------------------------------------------------------- 1 | assertNull(TimePointFactory::fromTimestamp(null)); 14 | $this->assertNull(TimePointFactory::fromTimestamp(0)); 15 | $this->assertNull(TimePointFactory::fromTimestamp(false)); 16 | $this->assertNull(TimePointFactory::fromTimestamp('times 5')); 17 | } 18 | 19 | public function testFromTimestampWhenValidValueGiven() 20 | { 21 | $this->assertEquals(new TimePoint(1970, 1, 1, 0, 0, 5), TimePointFactory::fromTimestamp(5)); 22 | $this->assertEquals(new TimePoint(1970, 1, 1, 0, 0, 2), TimePointFactory::fromTimestamp('2*5'), 'should return UNIX time begin + 2 seconds because string starts with a number'); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/TimeOfDayTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(true, $first->isBefore($second)); 18 | $this->assertEquals(true, $third->isAfter($second)); 19 | $this->assertEquals(true, $four->isEquals($third)); 20 | } 21 | 22 | public function testHowToKnowIfItIsTheAnteMeridianPostMeridian() 23 | { 24 | $ante = new TimeOfDay(11, 59, 59); 25 | $post = new TimeOfDay(12, 37, 21); 26 | $this->assertEquals(true, $ante->isAnteMeridian()); 27 | $this->assertEquals(true, $post->isPostMeridian()); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Factory/DateIntervalFactoryTest.php: -------------------------------------------------------------------------------- 1 | fail('An exception should be thrown'); 17 | } catch (\InvalidArgumentException $e) { 18 | $this->assertEquals('The given interval "2010-01,2010-01-02" does not respect the expected format: "Y-m-d,Y-m-d".', $e->getMessage()); 19 | } 20 | } 21 | 22 | public function testCreateWhenValidFormat() 23 | { 24 | $interval = DateIntervalFactory::create('2010-01-01', '2010-01-02'); 25 | $this->assertEquals(new DateInterval(new Date(2010, 1, 1), new Date(2010, 1, 2)), $interval); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ddd/components", 3 | "type": "library", 4 | "description": "Domain Driven Design components (Slug...).", 5 | "keywords": ["slugifier", "slug", "url", "DDD", "Domain Driven Design"], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Joseph Rouff", 10 | "email": "rouffj@gmail.com" 11 | }, 12 | { 13 | "name": "Jean-François Simon", 14 | "email": "contact@jfsimon.fr" 15 | } 16 | ], 17 | "require": { 18 | "php": ">=5.3.0" 19 | }, 20 | "suggest": { 21 | "swiftmailer/swiftmailer": "[Mailer] Allow use of SwiftMailer as MailerInterface implementation", 22 | "aws/aws-sdk-php": "[Mailer] Allow to use Amazon SES as MailerInterface implementation" 23 | }, 24 | "require-dev": { 25 | "doctrine/orm": "2.3", 26 | "swiftmailer/swiftmailer": "*", 27 | "aws/aws-sdk-php": "*" 28 | }, 29 | "autoload": { 30 | "psr-0": { "Ddd": "src/" } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Ddd/Time/Factory/TimePointFactory.php: -------------------------------------------------------------------------------- 1 | setTimestamp($timestamp); 25 | 26 | return self::fromDateTime($dateTime); 27 | } 28 | 29 | static public function fromDateTime(\DateTime $dateTime) 30 | { 31 | return new TimePoint( 32 | $dateTime->format('Y'), 33 | $dateTime->format('m'), 34 | $dateTime->format('d'), 35 | $dateTime->format('H'), 36 | $dateTime->format('i'), 37 | $dateTime->format('s') 38 | ); 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Strategy/FrozenStrategy.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class FrozenStrategy implements StrategyInterface 14 | { 15 | /** 16 | * {@inheritdoc} 17 | */ 18 | public function add(EventInterface $newEvent, array $events) 19 | { 20 | throw CalendarEventException::addWhileFrozen($newEvent); 21 | } 22 | 23 | /** 24 | * {@inheritdoc} 25 | */ 26 | public function remove(EventInterface $removedEvent, array $events) 27 | { 28 | throw CalendarEventException::removeWhileFrozen($removedEvent); 29 | } 30 | /** 31 | * {@inheritdoc} 32 | */ 33 | public function update(EventInterface $originalEvent, EventInterface $updatedEvent, array $events) 34 | { 35 | throw CalendarEventException::updateWhileFrozen($originalEvent); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Factory/TimeIntervalFactoryTest.php: -------------------------------------------------------------------------------- 1 | fail('An exception should be thrown'); 17 | } catch (\InvalidArgumentException $e) { 18 | $this->assertEquals('The given interval "2010-01-01 00,2010-01-01 05:00" does not respect the expected format: "Y-m-d G:i,Y-m-d G:i".', $e->getMessage()); 19 | } 20 | } 21 | 22 | public function testCreateWhenValidFormat() 23 | { 24 | $interval = TimeIntervalFactory::create('2010-01-01 00:00', '2010-01-01 05:00'); 25 | $this->assertEquals(new TimeInterval(new TimePoint(2010, 1, 1, 0, 0), new TimePoint(2010, 1, 1, 5, 0)), $interval); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Ddd/Time/Factory/DateIntervalFactory.php: -------------------------------------------------------------------------------- 1 | format('Y'), 18 | $now->format('m'), 19 | $now->format('d') 20 | ); 21 | } 22 | 23 | static public function create($beginString, $endString) 24 | { 25 | $begin = \DateTime::createFromFormat(self::FORMAT_DATE, $beginString); 26 | $end = \DateTime::createFromFormat(self::FORMAT_DATE, $endString); 27 | 28 | if (!$begin || !$end) { 29 | throw new \InvalidArgumentException(sprintf('The given interval "%s,%s" does not respect the expected format: "%s,%s".', $beginString, $endString, self::FORMAT_DATE, self::FORMAT_DATE)); 30 | } 31 | 32 | return new DateInterval(DateFactory::fromDateTime($begin), DateFactory::fromDateTime($end)); 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/NamedEvent.php: -------------------------------------------------------------------------------- 1 | title = $title; 27 | } 28 | 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function getTitle() 33 | { 34 | return $this->title; 35 | } 36 | 37 | /** 38 | * @param string $description 39 | */ 40 | public function setDescription($description) 41 | { 42 | $this->description = $description; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function getDescription() 49 | { 50 | return $this->description; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Tests/Acceptance/MailBuilderTest.php: -------------------------------------------------------------------------------- 1 | addRecipients(array( 18 | 'recipient1@bar.com', 19 | 'recipient2@bar.com' => 'Recipient 2', 20 | 'recipient3@bar.com', 21 | )) 22 | ->compose('My subject', 'My body') 23 | ; 24 | 25 | $mail = $builder->getTextMail(); 26 | 27 | $expectedMail = new TextMail(new Contact('sender@foo.bar', 'John Doo')); 28 | $expectedMail 29 | ->addRecipient(new Contact('recipient1@bar.com')) 30 | ->addRecipient(new Contact('recipient2@bar.com', 'Recipient 2')) 31 | ->addRecipient(new Contact('recipient3@bar.com')) 32 | ->compose('My subject', 'My body') 33 | ; 34 | $this->assertEquals($expectedMail, $mail); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Tests/Fixtures/DoctrineArticle.php: -------------------------------------------------------------------------------- 1 | id; 29 | } 30 | 31 | public function slugify(SlugGeneratorInterface $slugifier) 32 | { 33 | $this->slug = $slugifier->slugify(array($this->title)); 34 | } 35 | 36 | public function setTitle($title) 37 | { 38 | $this->title = $title; 39 | } 40 | 41 | public function getTitle() 42 | { 43 | return $this->title; 44 | } 45 | 46 | public function getSlug() 47 | { 48 | return $this->slug; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Ddd/Time/Bridge/Doctrine/Types/TimePointType.php: -------------------------------------------------------------------------------- 1 | getDateTimeTypeDeclarationSQL($fieldDeclaration); 15 | } 16 | 17 | public function convertToPHPValue($value, AbstractPlatform $platform) 18 | { 19 | $dtime = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value); 20 | if (!$dtime) { 21 | throw ConversionException::conversionFailedFormat($value, $this->getName(), $platform->getDateTimeFormatString()); 22 | } 23 | 24 | return TimePointFactory::fromDateTime($dtime); 25 | } 26 | 27 | public function convertToDatabaseValue($timepoint, AbstractPlatform $platform) 28 | { 29 | if ($timepoint !== null) { 30 | $dtime = $timepoint->toDateTime(); 31 | return $dtime->format($platform->getDateTimeFormatString()); 32 | } 33 | } 34 | 35 | public function getName() 36 | { 37 | return self::TIMEPOINT; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Ddd/Time/Bridge/Doctrine/Types/DateIntervalType.php: -------------------------------------------------------------------------------- 1 | getVarcharTypeDeclarationSQL($fieldDeclaration); 15 | } 16 | 17 | public function convertToPHPValue($dateIntervalFromDatabase, AbstractPlatform $platform) 18 | { 19 | list($begin, $end) = explode(',', $dateIntervalFromDatabase); 20 | 21 | return DateIntervalFactory::create($begin, $end); 22 | } 23 | 24 | public function convertToDatabaseValue($dateInterval, AbstractPlatform $platform) 25 | { 26 | if ($dateInterval !== null) { 27 | $beginString = $dateInterval->getBegin()->toDateTime()->format($platform->getDateFormatString()); 28 | $endString = $dateInterval->getEnd()->toDateTime()->format($platform->getDateFormatString()); 29 | } 30 | 31 | return sprintf('%s,%s', $beginString, $endString); 32 | } 33 | 34 | public function getName() 35 | { 36 | return self::DATE_INTERVAL; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Tests/HowTo/DoctorCalendarRepository.php: -------------------------------------------------------------------------------- 1 | calendar = new Calendar('Doctor Smith\'s appointments', array( 20 | new Event(TimeIntervalFactory::create('2012-01-01 8:00', '2012-01-01 09:00')), 21 | new Event(TimeIntervalFactory::create('2012-01-05 8:00', '2012-01-05 10:15')), 22 | new Event(TimeIntervalFactory::create('2012-01-10 15:00', '2012-01-10 15:30')), 23 | )); 24 | } 25 | 26 | public function load() 27 | { 28 | return $this->calendar; 29 | } 30 | 31 | public function loadInterval(TimeInterval $interval) 32 | { 33 | return $this->calendar->between($interval); 34 | } 35 | 36 | public function persist(CalendarInterface $calendar) 37 | { 38 | $this->calendar = $calendar; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Ddd/Time/Factory/TimeIntervalFactory.php: -------------------------------------------------------------------------------- 1 | getBegin(); 28 | $end = $dateInterval->getEnd(); 29 | 30 | return new TimeInterval( 31 | new TimePoint($begin->getYear(), $begin->getMonth(), $begin->getDay(), 0, 0), 32 | new TimePoint($end->getYear(), $end->getMonth(), $end->getDay(), 23, 59, 59) 33 | ); 34 | } 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/Ddd/Time/Bridge/Doctrine/Types/TimeIntervalType.php: -------------------------------------------------------------------------------- 1 | getVarcharTypeDeclarationSQL($fieldDeclaration); 15 | } 16 | 17 | public function convertToPHPValue($timepointIntervalFromDatabase, AbstractPlatform $platform) 18 | { 19 | list($begin, $end) = explode(',', $timepointIntervalFromDatabase); 20 | 21 | return TimeIntervalFactory::create($begin, $end); 22 | } 23 | 24 | public function convertToDatabaseValue($timepointInterval, AbstractPlatform $platform) 25 | { 26 | if ($timepointInterval !== null) { 27 | $beginString = $timepointInterval->getBegin()->toDateTime()->format($platform->getDateTimeFormatString()); 28 | $endString = $timepointInterval->getEnd()->toDateTime()->format($platform->getDateTimeFormatString()); 29 | } 30 | 31 | return sprintf('%s,%s', $beginString, $endString); 32 | } 33 | 34 | public function getName() 35 | { 36 | return self::TIME_INTERVAL; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Infra/Transliterator/LatinTransliterator.php: -------------------------------------------------------------------------------- 1 | 9 | * @author Jean-François Simon 10 | */ 11 | class LatinTransliterator implements TransliteratorInterface 12 | { 13 | /** 14 | * @var string 15 | */ 16 | private $inputEncoding; 17 | 18 | /** 19 | * @todo: enumerate here all possible accents 20 | */ 21 | private $availableAccents = array( 22 | '\'', '`', '^', '~' 23 | ); 24 | 25 | /** 26 | * @param string $inputEncoding 27 | */ 28 | public function __construct($inputEncoding = 'utf-8') 29 | { 30 | $this->inputEncoding = $inputEncoding; 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | public function transliterate($string) 37 | { 38 | $transliteration = iconv($this->inputEncoding, 'us-ascii//TRANSLIT', $string); 39 | 40 | return ('Darwin' === PHP_OS) ? $this->removeAloneAccents($transliteration) : $transliteration; 41 | } 42 | 43 | public function getName() 44 | { 45 | return 'latin'; 46 | } 47 | 48 | private function removeAloneAccents($transliteration) 49 | { 50 | return str_replace($this->availableAccents, '', $transliteration); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/SendableEvent.php: -------------------------------------------------------------------------------- 1 | organizer = $organizer; 27 | $this->guests = array(); 28 | } 29 | 30 | /** 31 | * @return string 32 | */ 33 | public function getOrganizer() 34 | { 35 | return $this->organizer; 36 | } 37 | 38 | public function addGuest($guest) 39 | { 40 | $this->guests[] = $guest; 41 | } 42 | 43 | public function removeGuest($guest) 44 | { 45 | if ($index = array_search($guest, $this->guests)) { 46 | array_slice($this->guests, $index, 1); 47 | } 48 | } 49 | 50 | public function hasGuest($guest) 51 | { 52 | return in_array($guest, $this->guests); 53 | } 54 | 55 | /** 56 | * @return array 57 | */ 58 | public function getGuests() 59 | { 60 | return $this->guests; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Ddd/Mail/MailBuilder.php: -------------------------------------------------------------------------------- 1 | from = new Contact($senderAddress, $senderName); 18 | } 19 | 20 | public static function create($senderAddress, $senderName) 21 | { 22 | return new static($senderAddress, $senderName); 23 | } 24 | 25 | public function addRecipients(array $recipients) 26 | { 27 | foreach ($recipients as $key => $value) { 28 | if (is_int($key)) { 29 | $recipient = new Contact($value, null); 30 | } else { 31 | $recipient = new Contact($key, $value); 32 | } 33 | 34 | $this->recipients[$recipient->getEmail()] = $recipient; 35 | } 36 | 37 | return $this; 38 | } 39 | 40 | public function compose($subject, $body) 41 | { 42 | $this->subject = $subject; 43 | $this->body = $body; 44 | 45 | return $this; 46 | } 47 | 48 | public function getTextMail() 49 | { 50 | $mail = new TextMail($this->from); 51 | $mail->compose($this->subject, $this->body); 52 | foreach ($this->recipients as $recipient) { 53 | $mail->addRecipient($recipient); 54 | } 55 | 56 | return $mail; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/FixedDate.php: -------------------------------------------------------------------------------- 1 | month = (null === $month) ? null : (int) $month; 13 | $this->day = (int) $day; 14 | } 15 | 16 | public function isAfter(Date $date) 17 | { 18 | if (!$this->month) { 19 | return $this->day > $date->getDay(); 20 | } 21 | 22 | return 23 | $this->month > $date->getMonth() || 24 | ($this->month >= $date->getMonth() && $this->day > $date->getDay()) 25 | ; 26 | } 27 | 28 | public function isBefore(Date $date) 29 | { 30 | return 31 | false === $this->isAfter($date) && 32 | false === $this->isEquals($date) 33 | ; 34 | } 35 | 36 | public function isEquals(Date $date) 37 | { 38 | if (!$this->month) { 39 | return $this->day === $date->getDay(); 40 | } 41 | 42 | return 43 | $this->month === $date->getMonth() && 44 | $this->day === $date->getDay() 45 | ; 46 | } 47 | 48 | /** 49 | * Gets the value of month 50 | * 51 | * @return int 52 | */ 53 | public function getMonth() 54 | { 55 | return $this->month; 56 | } 57 | 58 | /** 59 | * Gets the value of day 60 | * 61 | * @return int 62 | */ 63 | public function getDay() 64 | { 65 | return $this->day; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/CalendarInterface.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | interface CalendarInterface extends \IteratorAggregate, \Countable, \ArrayAccess 17 | { 18 | /** 19 | * @param TimeInterval $interval 20 | * @param string $title 21 | * 22 | * @return CalendarInterface 23 | */ 24 | public function between(TimeInterval $interval, $title = ''); 25 | 26 | /** 27 | * @param EventInterface $newEvent 28 | */ 29 | public function add(EventInterface $newEvent); 30 | 31 | /** 32 | * @param EventInterface $event 33 | */ 34 | public function remove(EventInterface $event); 35 | 36 | /** 37 | * @param EventInterface $originalEvent 38 | * @param EventInterface $updatedEvent 39 | */ 40 | public function update(EventInterface $originalEvent, EventInterface $updatedEvent); 41 | 42 | /** 43 | * @param TimePoint $cursor 44 | */ 45 | public function setCursor(TimePoint $cursor); 46 | 47 | /** 48 | * @return TimePoint 49 | */ 50 | public function getCursor(); 51 | 52 | /** 53 | * @return string 54 | */ 55 | public function getTitle(); 56 | 57 | /** 58 | * {@inheritdoc} 59 | */ 60 | public function countRemaining(); 61 | } 62 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Strategy/StrategyInterface.php: -------------------------------------------------------------------------------- 1 | unit = $unit; 20 | } 21 | 22 | public function getCode() 23 | { 24 | return (self::MINUTE === $this->unit) ? 'M' : $this->unit; 25 | } 26 | 27 | public function getUnit() 28 | { 29 | return $this->unit; 30 | } 31 | 32 | public function isTime() 33 | { 34 | return 35 | self::HOUR === $this->unit || 36 | self::MINUTE === $this->unit || 37 | self::SECOND === $this->unit 38 | ; 39 | } 40 | 41 | static public function year() 42 | { 43 | return new self(self::YEAR); 44 | } 45 | 46 | static public function month() 47 | { 48 | return new self(self::MONTH); 49 | } 50 | 51 | static public function week() 52 | { 53 | return new self(self::WEEK); 54 | } 55 | 56 | static public function day() 57 | { 58 | return new self(self::DAY); 59 | } 60 | 61 | static public function hour() 62 | { 63 | return new self(self::HOUR); 64 | } 65 | 66 | static public function minute() 67 | { 68 | return new self(self::MINUTE); 69 | } 70 | 71 | static public function second() 72 | { 73 | return new self(self::SECOND); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/TimeIntervalTest.php: -------------------------------------------------------------------------------- 1 | markTestIncomplete(); 13 | } 14 | 15 | public function testHowToKnowIfATimeIntervalIsBeforeAfterDuringAGivenDateInterval() 16 | { 17 | $this->markTestIncomplete(); 18 | } 19 | 20 | public function testHowToKnowIfATimeIntervalIsBeforeAfterDuringAGivenDate() 21 | { 22 | $this->markTestIncomplete(); 23 | } 24 | 25 | public function testHowToKnowIfATimeIntervalIsBeforeAfterDuringAGivenDateTime() 26 | { 27 | $this->markTestIncomplete(); 28 | } 29 | 30 | public function testHowToTransformATimeIntervalIntoADateIntervalDestroyData() 31 | { 32 | $this->markTestIncomplete(); 33 | } 34 | 35 | public function testHowToKnowHowLongATimeIntervalAreInAtLeastSecondsMinutesHoursDaysWeeksYears() 36 | { 37 | $this->markTestIncomplete(); 38 | } 39 | 40 | /** 41 | * Use cases: 42 | * - Retrieve from a parameters file a time interval in its string represention. 43 | */ 44 | public function testHowToTransformStringRepresentationOfTimeIntervalIntoAnObject() 45 | { 46 | $intervalInString = '2013-01-01 04:00,2013-02-02 06:00'; 47 | list($begin, $end) = explode(',', $intervalInString); 48 | $interval = TimeIntervalFactory::create($begin, $end); 49 | 50 | $this->assertInstanceOf('Ddd\Time\Model\TimeInterval', $interval); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Strategy/BaseStrategy.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class BaseStrategy implements StrategyInterface 14 | { 15 | /** 16 | * {@inheritdoc} 17 | */ 18 | public function add(EventInterface $newEvent, array $events) 19 | { 20 | $index = 0; 21 | foreach ($events as $event) { 22 | if ($newEvent->getInterval()->isBefore($event->getInterval())) { 23 | array_splice($events, $index, 0, array($newEvent)); 24 | 25 | return $events; 26 | } 27 | $index ++; 28 | } 29 | $events[] = $newEvent; 30 | 31 | return $events; 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function remove(EventInterface $removedEvent, array $events) 38 | { 39 | $index = 0; 40 | foreach ($events as $event) { 41 | if ($removedEvent->isEquals($event)) { 42 | array_splice($events, $index, 1); 43 | } else { 44 | $index ++; 45 | } 46 | } 47 | 48 | return $events; 49 | } 50 | 51 | /** 52 | * {@inheritdoc} 53 | */ 54 | public function update(EventInterface $originalEvent, EventInterface $updatedEvent, array $events) 55 | { 56 | $events = $this->add($updatedEvent, $events); 57 | 58 | try { 59 | $events = $this->remove($originalEvent, $events); 60 | } catch (CalendarExceptionInterface $exception) { 61 | $this->remove($updatedEvent, $events); 62 | 63 | throw $exception; 64 | } 65 | 66 | return $events; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Infra/Mailer/SwiftMailer.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 18 | } 19 | 20 | public function send(Mail $mail) 21 | { 22 | $swiftMessage = $this->transform($mail); 23 | 24 | $failedRecipients = array(); 25 | $this->mailer->send($swiftMessage, $failedRecipients); 26 | $this->message = $swiftMessage; 27 | 28 | $contacts = array(); 29 | foreach ($failedRecipients as $recipient) { 30 | $contacts[] = new Contact($recipient); 31 | } 32 | 33 | return $contacts; 34 | } 35 | 36 | private function transform(Mail $mail) 37 | { 38 | $recipients = array(); 39 | foreach ($mail->getRecipients() as $contact) { 40 | $recipients[$contact->getEmail()] = $contact->getName(); 41 | } 42 | 43 | $message = \Swift_Message::newInstance() 44 | ->setCharset($mail->getCharset()) 45 | ->setFrom(array($mail->getFrom()->getEmail() => $mail->getFrom()->getName())) 46 | ->setTo($recipients) 47 | ->setSubject($mail->getSubject()) 48 | ->setBody($mail->getBody()) 49 | ; 50 | 51 | $contentType = ($mail instanceof TextMail) ? 'text/plain' : 'text/html'; 52 | $message->setContentType($contentType); 53 | 54 | return $message; 55 | } 56 | 57 | /** 58 | * Use this method only for testing purpose. 59 | * 60 | * @return Swift_Message 61 | */ 62 | public function getSentMessage() 63 | { 64 | return $this->message; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Infra/Mailer/AmazonSesMailer.php: -------------------------------------------------------------------------------- 1 | mailer = $mailer; 19 | } 20 | 21 | public function send(Mail $mail) 22 | { 23 | $amazonSesMessage = $this->transform($mail); 24 | 25 | $this->mailer->getCommand('SendEmail', $amazonSesMessage)->execute(); 26 | $this->message = $amazonSesMessage; 27 | } 28 | 29 | private function transform(Mail $mail) 30 | { 31 | $recipients = array(); 32 | foreach ($mail->getRecipients() as $contact) { 33 | $recipients[$contact->getEmail()] = $contact->getName(); 34 | } 35 | 36 | $message = array( 37 | 'Source' => $mail->getFrom()->toString(), 38 | 'Destination' => array( 39 | 'ToAddresses' => array_keys($recipients) 40 | ), 41 | 'Message' => array( 42 | 'Subject' => array( 43 | 'Data' => $mail->getSubject(), 44 | 'Charset' => $mail->getCharset(), 45 | ), 46 | 'Body' => array( 47 | 'Text' => array( 48 | 'Data' => $mail->getBody(), 49 | 'Charset' => $mail->getCharset(), 50 | ), 51 | ), 52 | ), 53 | ); 54 | 55 | return $message; 56 | } 57 | 58 | /** 59 | * Use this method only for testing purpose. 60 | * 61 | * @return Array 62 | */ 63 | public function getSentMessage() 64 | { 65 | return $this->message; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/TimeInterval.php: -------------------------------------------------------------------------------- 1 | begin = $begin; 13 | $this->end = $end; 14 | } 15 | 16 | public function isEquals(TimeInterval $interval) 17 | { 18 | return 19 | $this->begin->isEquals($interval->getBegin()) && 20 | $this->end->isEquals($interval->getEnd()) 21 | ; 22 | } 23 | 24 | public function isBefore(IntervalInterface $interval) 25 | { 26 | return $interval->getEnd()->isAfter($this->getBegin()) && $interval->getBegin()->isAfter($this->getEnd()); 27 | } 28 | 29 | public function isAfter(IntervalInterface $interval) 30 | { 31 | return $this->begin->isAfter($interval->getEnd()); 32 | } 33 | 34 | public function isDuring(IntervalInterface $interval) 35 | { 36 | return !$this->isBefore($interval) && !$this->isAfter($interval); 37 | } 38 | 39 | public function isPartiallyBefore(IntervalInterface $interval) 40 | { 41 | throw new \Exception('Not implemented'); 42 | } 43 | 44 | public function isPartiallyAfter(IntervalInterface $interval) 45 | { 46 | throw new \Exception('Not implemented'); 47 | } 48 | 49 | public function getBegin() 50 | { 51 | return $this->begin; 52 | } 53 | 54 | public function getEnd() 55 | { 56 | return $this->end; 57 | } 58 | 59 | public function getLength() 60 | { 61 | $begin = $this->begin->toDateTime(); 62 | $end = $this->end->toDateTime(); 63 | $diff = $begin->diff($end); 64 | 65 | return new Duration($diff->format('%H'), TimeUnit::hour()); 66 | } 67 | 68 | public function isInclude(IntervalInterface $other) 69 | { 70 | throw new \Exception('Not yet implemented.'); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Tests/HowTo/CalendarTest.php: -------------------------------------------------------------------------------- 1 | calendar = $repository->load(); 20 | } 21 | 22 | public function testHowToLoadEventsFromDatastore() 23 | { 24 | $this->markTestIncomplete(); 25 | } 26 | 27 | public function testHowToRetrieveAllMyAppointments() 28 | { 29 | $this->assertSame('Doctor Smith\'s appointments', $this->calendar->getTitle()); 30 | $this->assertCount(3, $this->calendar); 31 | } 32 | 33 | public function testHowToRetrieveMyAppointmentsForToday() 34 | { 35 | $today = DateIntervalFactory::create('2012-01-01', '2012-01-01'); 36 | $this->assertCount(1, $this->calendar->between(TimeIntervalFactory::fromDateInterval($today))); 37 | } 38 | 39 | public function testHowToRetrieveAppointmentsAfterADate() 40 | { 41 | $today = new TimePoint(2012, 1, 1, 10, 0); 42 | $this->calendar->setCursor($today); 43 | $this->assertSame(2, $this->calendar->countRemaining()); 44 | } 45 | 46 | public function testHowToRetrieveMyAppointmentsForCurrentWeek() 47 | { 48 | $week = DateIntervalFactory::create('2012-01-01', '2012-01-07'); 49 | $this->assertCount(2, $this->calendar->between(TimeIntervalFactory::fromDateInterval($week))); 50 | } 51 | 52 | public function testHowToAddNewAppointment() 53 | { 54 | $event = new Event(TimeIntervalFactory::create('2012-01-01 17:00', '2012-01-01 18:00')); 55 | $this->calendar->add($event); 56 | $this->assertCount(4, $this->calendar); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Exception/CalendarEventException.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class CalendarEventException extends \LogicException implements CalendarExceptionInterface 13 | { 14 | /** 15 | * @var EventInterface 16 | */ 17 | private $event; 18 | 19 | /** 20 | * @param EventInterface $event 21 | * 22 | * @return CalendarEventException 23 | */ 24 | public static function addWhileFrozen(EventInterface $event) 25 | { 26 | return new self($event, 'Cannot add event to frozen calendar.'); 27 | } 28 | 29 | /** 30 | * @param EventInterface $event 31 | * 32 | * @return CalendarEventException 33 | */ 34 | public static function removeWhileFrozen(EventInterface $event) 35 | { 36 | return new self($event, 'Cannot remove event from frozen calendar.'); 37 | } 38 | 39 | 40 | /** 41 | * @param EventInterface $event 42 | * 43 | * @return CalendarEventException 44 | */ 45 | public static function updateWhileFrozen(EventInterface $event) 46 | { 47 | return new self($event, 'Cannot update event from frozen calendar.'); 48 | } 49 | 50 | /** 51 | * @param EventInterface $event 52 | * 53 | * @return CalendarEventException 54 | */ 55 | public static function eventOverlap(EventInterface $event) 56 | { 57 | return new self($event, 'Events overlap detected.'); 58 | } 59 | 60 | /** 61 | * @param EventInterface $event 62 | * @param int $message 63 | */ 64 | public function __construct(EventInterface $event, $message) 65 | { 66 | parent::__construct($message); 67 | $this->event = $event; 68 | } 69 | 70 | /** 71 | * @return EventInterface 72 | */ 73 | public function getEvent() 74 | { 75 | return $this->event; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Model/Mail.php: -------------------------------------------------------------------------------- 1 | from = $from; 21 | $this->charset = 'utf-8'; 22 | } 23 | 24 | public function compose($subject, $body) 25 | { 26 | $this->subject = $subject; 27 | $this->body = $body; 28 | 29 | return $this; 30 | } 31 | 32 | public function addRecipient(Contact $recipient) 33 | { 34 | $this->recipients[] = $recipient; 35 | 36 | return $this; 37 | } 38 | 39 | public function send(MailerInterface $mailer) 40 | { 41 | if (null === $this->subject && null === $this->body) { 42 | throw new MailNotComposedException(); 43 | } 44 | 45 | if (0 === count($this->recipients)) { 46 | throw new MailWithoutRecipientException(); 47 | } 48 | 49 | $this->failedRecipients = $mailer->send($this); 50 | if (0 === count($this->failedRecipients)) { 51 | $this->sent = true; 52 | } 53 | } 54 | 55 | public function isSent() 56 | { 57 | return $this->sent; 58 | } 59 | 60 | public function getRecipients() 61 | { 62 | return $this->recipients; 63 | } 64 | 65 | public function getFrom() 66 | { 67 | return $this->from; 68 | } 69 | 70 | public function getFailedRecipients() 71 | { 72 | return $this->failedRecipients; 73 | } 74 | 75 | public function getSubject() 76 | { 77 | return $this->subject; 78 | } 79 | 80 | public function getBody() 81 | { 82 | return $this->body; 83 | } 84 | 85 | public function getCharset() 86 | { 87 | return $this->charset; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/DateIntervalTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(new Duration(0, TimeUnit::day()), $interval->getDuration()); 19 | 20 | $interval = new DateInterval(new Date(2012, 01, 01), new Date(2012, 01, 03)); 21 | $this->assertEquals(new Duration(2, TimeUnit::day()), $interval->getDuration()); 22 | } 23 | 24 | public function testNextEquals() 25 | { 26 | $startDate = new Date(2012, 01, 01); 27 | $endDate = new Date(2012, 01, 03); 28 | 29 | $interval = new DateInterval($startDate, $endDate); 30 | $this->assertEquals($startDate, $interval->getBegin()); 31 | $this->assertEquals(new Date(2012, 01, 02), $interval->getBegin()->next()); 32 | $this->assertEquals(new Date(2012, 01, 03), $interval->getBegin()->next()->next()); 33 | 34 | $this->assertFalse($endDate->isEquals($interval->getBegin())); 35 | $this->assertFalse($endDate->isEquals($interval->getBegin()->next())); 36 | $this->assertTrue($endDate->isEquals($interval->getBegin()->next()->next())); 37 | } 38 | 39 | public function testIsInclude() 40 | { 41 | $interval = DateIntervalFactory::create('2013-01-10', '2013-01-20'); 42 | 43 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-01-13', '2013-01-14'))); 44 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-01-13', '2013-01-15'))); 45 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-01-14', '2013-01-15'))); 46 | $this->assertTrue($interval->isInclude(TimeIntervalFactory::create('2013-01-13 01:00', '2013-01-14 18:30'))); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Strategy/PersistenceStrategy.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class PersistenceStrategyDecorator implements StrategyInterface 16 | { 17 | /** 18 | * @var CalendarInterface 19 | */ 20 | private $calendar; 21 | 22 | /** 23 | * @var StrategyInterface 24 | */ 25 | private $innerStrategy; 26 | 27 | /** 28 | * @var CalendarPersisterInterface 29 | */ 30 | private $persister; 31 | 32 | /** 33 | * @param CalendarInterface $calendar 34 | * @param StrategyInterface $innerStrategy 35 | * @param CalendarPersisterInterface $persister 36 | */ 37 | public function __construct(CalendarInterface $calendar, StrategyInterface $innerStrategy, CalendarPersisterInterface $persister) 38 | { 39 | $this->calendar = $calendar; 40 | $this->innerStrategy = $innerStrategy; 41 | $this->persister = $persister; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function add(EventInterface $newEvent, array $events) 48 | { 49 | $result = $this->innerStrategy->add($newEvent, $events); 50 | $this->persister->persist($this->calendar); 51 | 52 | return $result; 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function remove(EventInterface $removedEvent, array $events) 59 | { 60 | $result = $this->innerStrategy->remove($removedEvent, $events); 61 | $this->persister->persist($this->calendar); 62 | 63 | return $result; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function update(EventInterface $originalEvent, EventInterface $updatedEvent, array $events) 70 | { 71 | return $this->innerStrategy->update($originalEvent, $updatedEvent, $events); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/FixedDateInterval.php: -------------------------------------------------------------------------------- 1 | begin = $begin; 13 | $this->end = $end; 14 | } 15 | 16 | /** 17 | * Gets the begin value 18 | * 19 | * @return Date 20 | */ 21 | public function getBegin() 22 | { 23 | return $this->begin; 24 | } 25 | 26 | /** 27 | * Gets the end value 28 | * 29 | * @return Date 30 | */ 31 | public function getEnd() 32 | { 33 | return $this->end; 34 | } 35 | 36 | public function isInclude(IntervalInterface $other) 37 | { 38 | if ($other instanceof TimeInterval) { 39 | $otherBegin = $other->getBegin()->getDate(); 40 | $otherEnd = $other->getEnd()->getDate(); 41 | } else { 42 | $otherBegin = $other->getBegin(); 43 | $otherEnd = $other->getEnd(); 44 | } 45 | 46 | return 47 | ($this->begin->isBefore($otherBegin) || $this->begin->isEquals($otherBegin)) && 48 | ($this->end->isAfter($otherEnd) || $this->end->isEquals($otherEnd)) 49 | ; 50 | } 51 | 52 | /** 53 | * @param IntervalInterface $other 54 | * @return bool 55 | */ 56 | public function isBefore(IntervalInterface $other) 57 | { 58 | throw new \Exception('Not implemented'); 59 | } 60 | 61 | /** 62 | * @param IntervalInterface $other 63 | * @return bool 64 | */ 65 | public function isAfter(IntervalInterface $other) 66 | { 67 | throw new \Exception('Not implemented'); 68 | } 69 | 70 | /** 71 | * @param IntervalInterface $other 72 | * @return bool 73 | */ 74 | public function isDuring(IntervalInterface $other) 75 | { 76 | throw new \Exception('Not implemented'); 77 | } 78 | 79 | public function isPartiallyBefore(IntervalInterface $interval) 80 | { 81 | throw new \Exception('Not implemented'); 82 | } 83 | 84 | public function isPartiallyAfter(IntervalInterface $interval) 85 | { 86 | throw new \Exception('Not implemented'); 87 | } 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/TimeOfDay.php: -------------------------------------------------------------------------------- 1 | hour = (int)$hour; 14 | $this->minutes = (int)$minutes; 15 | $this->seconds = (int)$seconds; 16 | } 17 | 18 | public function isEquals(TimeOfDay $other) 19 | { 20 | return 21 | $this->hour === $other->getHour() && 22 | $this->minutes === $other->getMinutes() && 23 | $this->seconds === $other->getSeconds() 24 | ; 25 | } 26 | 27 | public function isBefore(TimeOfDay $other) 28 | { 29 | return 30 | false === $this->isEquals($other) && 31 | false === $this->isAfter($other); 32 | } 33 | 34 | public function isAfter(TimeOfDay $other) 35 | { 36 | return 37 | $this->hour > $other->getHour() || 38 | ($this->hour === $other->getHour() && $this->minutes > $other->getMinutes()) || 39 | ($this->hour === $other->getHour() && $this->minutes === $other->getMinutes() && $this->seconds > $other->getSeconds()) 40 | ; 41 | } 42 | 43 | public function isAnteMeridian() 44 | { 45 | return $this->hour < 12; 46 | } 47 | 48 | public function isPostMeridian() 49 | { 50 | return false === $this->isAnteMeridian(); 51 | } 52 | 53 | public function __toString() 54 | { 55 | $hour = ($this->hour < 10) ? '0'.$this->hour : $this->hour; 56 | $minutes = ($this->minutes < 10) ? '0'.$this->minutes : $this->minutes; 57 | 58 | return $hour.':'.$minutes; 59 | } 60 | 61 | /** 62 | * Gets the value of hour 63 | * 64 | * @return int 65 | */ 66 | public function getHour() 67 | { 68 | return $this->hour; 69 | } 70 | 71 | /** 72 | * Gets the value of minutes 73 | * 74 | * @return int 75 | */ 76 | public function getMinutes() 77 | { 78 | return $this->minutes; 79 | } 80 | 81 | /** 82 | * Gets the value of minutes 83 | * 84 | * @return int 85 | */ 86 | public function getSeconds() 87 | { 88 | return $this->seconds; 89 | } 90 | } 91 | 92 | -------------------------------------------------------------------------------- /src/Ddd/Slug/README.md: -------------------------------------------------------------------------------- 1 | Slug: an agnostic slug generator 2 | ================================ 3 | 4 | **Slug** is a component which generates slugs easily whatever persistence 5 | mecanism you use (Propel2, Doctrine2, custom ORM...). 6 | 7 | To generate a slug of a string there is always two 2 steps: 8 | 9 | - The transliteration step which converts a given string from any writing system 10 | (French, Deutsh, Greek, Arabic...) into its ASCII representation. 11 | - The slug generation step which basically separates each word and field by a custom delimiter. 12 | 13 | Therefore **Slug** component has 2 services: `TransliteratorInterface` and `SlugGeneratorInterface`. Each of these services 14 | can have multiple implementations: 15 | 16 | - `LatinTransliterator`: Transliterate a string written in any Latin 17 | alphabet (French, Deutsh, Spanish...) into its ASCII equivalent. 18 | - `DefaultSlugGenerator`: Customize the word and field separator. 19 | - `PatternSlugGenerator`: Complete customization of slug generation. 20 | 21 | Installation 22 | ------------ 23 | 24 | Using Composer, just require the `ddd/components` package: 25 | 26 | ``` javascript 27 | { 28 | "require": { 29 | "ddd/components": "dev-master" 30 | } 31 | } 32 | ``` 33 | 34 | Usage 35 | ----- 36 | 37 | To be able to slugify an entity or model, you just have to implement the `SluggableInterface`: 38 | 39 | ``` php 40 | slug = $slugifier->slugify(array($this->createdAt->format('Y'), $this->title)); 54 | } 55 | 56 | // other methods... 57 | } 58 | ``` 59 | 60 | Then you just have to call the `slugify` method to generate the slug: 61 | 62 | ``` php 63 | use Ddd\Slug\Infra\SlugGenerator\DefaultSlugGenerator; 64 | use Ddd\Slug\Infra\Transliterator\LatinTransliterator; 65 | 66 | $article = new Article(); 67 | $article->setTitle('Hello world!'); 68 | $article->slugify(new DefaultSlugGenerator(array(new LatinTransliterator()))); 69 | 70 | echo $article->getSlug(); // writes "2013-hello-world" 71 | ``` 72 | 73 | Credits 74 | ------- 75 | 76 | - Joseph Rouff 77 | - Jean-François Simon 78 | 79 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Infra/Transliterator/TransliteratorCollection.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class TransliteratorCollection 11 | { 12 | /** 13 | * @var TransliteratorInterface[] 14 | */ 15 | private $transliterators = array(); 16 | 17 | /** 18 | * @param TransliteratorInterface[] $transliterators 19 | */ 20 | public function __construct(array $transliterators) 21 | { 22 | foreach ($transliterators as $transliterator) { 23 | $this->add($transliterator); 24 | } 25 | } 26 | 27 | /** 28 | * @param TransliteratorInterface $transliterator 29 | * 30 | * @return TransliteratorCollection 31 | */ 32 | public function add(TransliteratorInterface $transliterator) 33 | { 34 | $this->transliterators[$transliterator->getName()] = $transliterator; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Transliterates string with named transliterator. 41 | * 42 | * @param string $name Transliterator name 43 | * @param string $string String to transliterate 44 | * 45 | * @throws \InvalidArgumentException If transliterator not found 46 | * 47 | * @return string Transliterated string 48 | */ 49 | public function transliterate($name, $string) 50 | { 51 | if (!isset($this->transliterators[$name])) { 52 | throw new \InvalidArgumentException(sprintf( 53 | 'Unknwon transliterator "%s", known ones are "%s".', 54 | $name, 55 | implode('", "', array_keys($this->transliterators)) 56 | )); 57 | } 58 | 59 | return $this->transliterators[$name]->transliterate($string); 60 | } 61 | 62 | /** 63 | * @param string $name 64 | * 65 | * @return boolean 66 | */ 67 | public function has($name) 68 | { 69 | return isset($this->transliterators[$name]); 70 | } 71 | 72 | /** 73 | * @param string $name 74 | * 75 | * @return TransliteratorInterface 76 | * 77 | * @throws \InvalidArgumentException 78 | */ 79 | public function get($name) 80 | { 81 | if (!isset($this->transliterators[$name])) { 82 | throw new \InvalidArgumentException('Transliterator "'.$name.'" does not exist.'); 83 | } 84 | 85 | return $this->transliterators[$name]; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/TimePointTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(new TimePoint(2015, 1, 1, 9, 30), $point->plus(new Duration(3, TimeUnit::year()))); 18 | $this->assertEquals(new TimePoint(2012, 5, 1, 9, 30), $point->plus(new Duration(4, TimeUnit::month()))); 19 | $this->assertEquals(new TimePoint(2012, 1, 3, 9, 30), $point->plus(new Duration(2, TimeUnit::day()))); 20 | $this->assertEquals(new TimePoint(2012, 1, 1, 12, 30), $point->plus(new Duration(3, TimeUnit::hour()))); 21 | $this->assertEquals(new TimePoint(2012, 1, 1, 10, 0), $point->plus(new Duration(30, TimeUnit::minute()))); 22 | } 23 | 24 | public function testMinus() 25 | { 26 | $point = new TimePoint(2012, 1, 1, 9, 30); 27 | 28 | $this->assertEquals(new TimePoint(2009, 1, 1, 9, 30), $point->minus(new Duration(3, TimeUnit::year()))); 29 | $this->assertEquals(new TimePoint(2011, 9, 1, 9, 30), $point->minus(new Duration(4, TimeUnit::month()))); 30 | $this->assertEquals(new TimePoint(2011, 12, 30, 9, 30), $point->minus(new Duration(2, TimeUnit::day()))); 31 | $this->assertEquals(new TimePoint(2012, 1, 1, 6, 30), $point->minus(new Duration(3, TimeUnit::hour()))); 32 | $this->assertEquals(new TimePoint(2012, 1, 1, 9, 0), $point->minus(new Duration(30, TimeUnit::minute()))); 33 | } 34 | 35 | public function testUntilDuring() 36 | { 37 | $point = new TimePoint(2012, 1, 1, 9, 30); 38 | 39 | $expectedInterval = new TimeInterval(new TimePoint(2012, 1, 1, 9, 30), new TimePoint(2012, 1, 1, 13, 30)); 40 | $this->assertTrue($expectedInterval->isEquals($point->during(new Duration(4, TimeUnit::hour())))); 41 | $this->assertTrue($expectedInterval->isEquals($point->until(new TimePoint(2012, 1, 1, 13, 30)))); 42 | } 43 | 44 | public function testIsAfter() 45 | { 46 | $point = new TimePoint(2012, 2, 1, 1, 0, 30); 47 | 48 | // second 49 | $this->assertTrue($point->isAfter(new TimePoint(2012, 2, 1, 1, 0, 29))); 50 | $this->assertFalse($point->isAfter(new TimePoint(2012, 2, 1, 1, 0, 30))); 51 | $this->assertFalse($point->isAfter(new TimePoint(2012, 2, 1, 1, 0, 31))); 52 | } 53 | 54 | public function testToTimePoint() 55 | { 56 | $point = new TimePoint(2013, 1, 1, 2, 30); 57 | $interval = $point->toTimeInterval(); 58 | 59 | $this->assertInstanceOf('Ddd\Time\Model\TimeInterval', $interval); 60 | $this->assertEquals(new TimeInterval($point, $point), $interval); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Infra/SlugGenerator/DefaultSlugGenerator.php: -------------------------------------------------------------------------------- 1 | 12 | * @author Jean-François Simon 13 | */ 14 | class DefaultSlugGenerator implements SlugGeneratorInterface 15 | { 16 | const REPLACED_CHARS = '~[^a-z0-9]~i'; 17 | 18 | /** 19 | * @var TransliteratorCollection 20 | */ 21 | private $transliterators; 22 | 23 | /** 24 | * @var array 25 | */ 26 | private $defaultOptions; 27 | 28 | /** 29 | * @param TransliteratorCollection $transliterators 30 | * @param array $defaultOptions 31 | */ 32 | public function __construct(TransliteratorCollection $transliterators, array $defaultOptions) 33 | { 34 | $this->transliterators = $transliterators; 35 | $this->defaultOptions = array_merge(array( 36 | 'word_separator' => '-', 37 | 'field_separator' => '-', 38 | 'transliterator' => 'latin', 39 | ), $defaultOptions); 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function slugify(array $fieldValues, array $options = array()) 46 | { 47 | $options = array_merge($this->defaultOptions, $options); 48 | 49 | if (!$this->validateOptions($options)) { 50 | throw new \InvalidArgumentException('Some of given options are not expected'); 51 | } 52 | 53 | $stringToSlugify = $this->transliterators->transliterate($options['transliterator'], implode($options['field_separator'], $fieldValues)); 54 | $slug = $this->replaceUnwantedChars($stringToSlugify, $options['word_separator']); 55 | $slug = $this->removeDuplicateWordSeparators($slug, $options['word_separator']); 56 | 57 | return trim(strtolower($slug), $options['word_separator']); 58 | } 59 | 60 | /** 61 | * @param array $options 62 | * 63 | * @return bool 64 | */ 65 | public function validateOptions(array $options) 66 | { 67 | return true; 68 | } 69 | 70 | /** 71 | * @param string $stringToSlugify 72 | * @param string $wordSeparator 73 | * 74 | * @return string 75 | */ 76 | private function replaceUnwantedChars($stringToSlugify, $wordSeparator) 77 | { 78 | return preg_replace(self::REPLACED_CHARS, $wordSeparator, $stringToSlugify); 79 | } 80 | 81 | /** 82 | * @param string $slug 83 | * @param string $wordSeparator 84 | * 85 | * @return string 86 | */ 87 | private function removeDuplicateWordSeparators($slug, $wordSeparator) 88 | { 89 | return preg_replace('~['.preg_quote($wordSeparator).']+~', $wordSeparator, $slug); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/FixedDateTest.php: -------------------------------------------------------------------------------- 1 | assertFalse($christmasDay->isAfter(new Date(2013, 12, 25))); 15 | $this->assertFalse($christmasDay->isAfter(new Date(2000, 12, 25))); 16 | $this->assertTrue($christmasDay->isAfter(new Date(2013, 12, 24))); 17 | $this->assertTrue($christmasDay->isAfter(new Date(2000, 12, 24))); 18 | $this->assertFalse($christmasDay->isAfter(new Date(2013, 12, 26))); 19 | $this->assertFalse($christmasDay->isAfter(new Date(2000, 12, 26))); 20 | } 21 | 22 | public function testIsAfterWhenMonthNotGiven() 23 | { 24 | $day25 = new FixedDate(null, 25); 25 | $this->assertTrue($day25->isAfter(new Date(2013, 12, 24))); 26 | $this->assertTrue($day25->isAfter(new Date(2013, 1, 24))); 27 | $this->assertTrue($day25->isAfter(new Date(2000, 5, 24))); 28 | } 29 | 30 | public function testIsBefore() 31 | { 32 | $christmasDay = new FixedDate(12, 25); 33 | $this->assertFalse($christmasDay->isBefore(new Date(2013, 12, 25))); 34 | $this->assertFalse($christmasDay->isBefore(new Date(2000, 12, 25))); 35 | $this->assertFalse($christmasDay->isBefore(new Date(2013, 12, 24))); 36 | $this->assertFalse($christmasDay->isBefore(new Date(2000, 12, 24))); 37 | $this->assertTrue($christmasDay->isBefore(new Date(2013, 12, 26))); 38 | $this->assertTrue($christmasDay->isBefore(new Date(2000, 12, 26))); 39 | } 40 | 41 | public function testIsBeforeWhenMonthNotGiven() 42 | { 43 | $day25 = new FixedDate(null, 25); 44 | $this->assertTrue($day25->isBefore(new Date(2013, 12, 26))); 45 | $this->assertTrue($day25->isBefore(new Date(2013, 1, 26))); 46 | $this->assertTrue($day25->isBefore(new Date(2000, 5, 26))); 47 | } 48 | 49 | public function testIsEquals() 50 | { 51 | $christmasDay = new FixedDate(12, 25); 52 | $this->assertTrue($christmasDay->isEquals(new Date(2013, 12, 25))); 53 | $this->assertTrue($christmasDay->isEquals(new Date(2000, 12, 25))); 54 | $this->assertFalse($christmasDay->isEquals(new Date(2013, 12, 24))); 55 | $this->assertFalse($christmasDay->isEquals(new Date(2000, 12, 24))); 56 | $this->assertFalse($christmasDay->isEquals(new Date(2013, 12, 26))); 57 | $this->assertFalse($christmasDay->isEquals(new Date(2000, 12, 26))); 58 | } 59 | 60 | public function testIsEqualsWhenMonthNotGiven() 61 | { 62 | $day25 = new FixedDate(null, 25); 63 | $this->assertTrue($day25->isEquals(new Date(2013, 12, 25))); 64 | $this->assertTrue($day25->isEquals(new Date(2013, 1, 25))); 65 | $this->assertTrue($day25->isEquals(new Date(2000, 5, 25))); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/DurationTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(new Duration(15840, TimeUnit::minute()), $duration1->toMinutes()); 16 | $this->assertEquals(new Duration(950400, TimeUnit::second()), $duration1->toSeconds()); 17 | $this->assertEquals(new Duration(72, TimeUnit::hour()), $duration2->toHours()); 18 | $this->assertEquals(new Duration(4320, TimeUnit::minute()), $duration2->toMinutes()); 19 | $this->assertEquals(new Duration(259200, TimeUnit::second()), $duration2->toSeconds()); 20 | } 21 | 22 | public function testHowToKnowHowLongXWeeksInDaysHoursMinutesSeconds() 23 | { 24 | $duration1 = new Duration(1, TimeUnit::week()); 25 | $this->assertEquals(new Duration(7, TimeUnit::day()), $duration1->toDays()); 26 | $this->assertEquals(new Duration(7*24, TimeUnit::hour()), $duration1->toHours()); 27 | $this->assertEquals(new Duration(7*24*60, TimeUnit::minute()), $duration1->toMinutes()); 28 | $this->assertEquals(new Duration(7*24*60*60, TimeUnit::second()), $duration1->toSeconds()); 29 | } 30 | 31 | public function testHowToKnowHowLongXMonthsInWeeksDaysHoursMinutesSeconds() 32 | { 33 | $duration1 = new Duration(2, TimeUnit::month(), 2013, 2); 34 | $duration2 = new Duration(2, TimeUnit::month(), 2012, 2); 35 | 36 | $this->assertEquals(new Duration(28+31, TimeUnit::day()), $duration1->toDays()); 37 | $this->assertEquals(new Duration(29+31, TimeUnit::day()), $duration2->toDays()); 38 | $this->assertEquals(new Duration((28+31)*24, TimeUnit::hour()), $duration1->toHours()); 39 | $this->assertEquals(new Duration((28+31)*24*60, TimeUnit::minute()), $duration1->toMinutes()); 40 | $this->assertEquals(new Duration((28+31)*24*60*60, TimeUnit::second()), $duration1->toSeconds()); 41 | } 42 | 43 | public function testHowToKnowHowLongXYearsInMonthsWeeksDaysHoursMinutesSeconds() 44 | { 45 | $duration1 = new Duration(1, TimeUnit::year(), 2013); 46 | $duration2 = new Duration(1, TimeUnit::year(), 2012); 47 | 48 | $this->assertEquals(new Duration(365, TimeUnit::day()), $duration1->toDays()); 49 | $this->assertEquals(new Duration(366, TimeUnit::day()), $duration2->toDays()); 50 | $this->assertEquals(new Duration(365*24, TimeUnit::hour()), $duration1->toHours()); 51 | $this->assertEquals(new Duration(365*24*60, TimeUnit::minute()), $duration1->toMinutes()); 52 | $this->assertEquals(new Duration(365*24*60*60, TimeUnit::second()), $duration1->toSeconds()); 53 | } 54 | 55 | public function testHowToKnowHowLongAYearsBMonthsCWeeksDDaysInHoursMinutesSeconds() 56 | { 57 | $this->markTestIncomplete(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Ddd/Slug/Tests/AcceptanceTest.php: -------------------------------------------------------------------------------- 1 | defaultSlugGenerator = new DefaultSlugGenerator($transliterators); 24 | $this->passthruSlugGenerator = new PassthruSlugGenerator(); 25 | } 26 | 27 | public function testEntityPassthruSlugification() 28 | { 29 | $title = 'Héllo slugifier!'; 30 | $article = new InMemoryArticle(); 31 | $article->setTitle($title); 32 | $article->slugify($this->passthruSlugGenerator); 33 | $this->assertEquals($title, $article->getSlug()); 34 | } 35 | 36 | /** @dataProvider Ddd\Slug\Tests\AcceptanceDataProvider::getEntityAsciiTextSlugificationData */ 37 | public function testEntityAsciiTextSlugification($title, $slug) 38 | { 39 | $article = new InMemoryArticle(); 40 | $article->setTitle($title); 41 | $article->slugify($this->defaultSlugGenerator); 42 | $this->assertEquals($slug, $article->getSlug()); 43 | } 44 | 45 | /** @dataProvider Ddd\Slug\Tests\AcceptanceDataProvider::getEntityLatinTransliteratedSlugificationData */ 46 | public function testEntityLatinTransliteratedSlugification($title, $slug) 47 | { 48 | $article = new InMemoryArticle(); 49 | $article->setTitle($title); 50 | $article->slugify($this->defaultSlugGenerator); 51 | $this->assertEquals($slug, $article->getSlug()); 52 | } 53 | 54 | public function testICouldUseSlugifyWithDoctrineOrm() 55 | { 56 | TestDatabase::backup(); 57 | 58 | // Doctrine setup 59 | $params = array('driver' => 'pdo_sqlite', 'path' => __DIR__.'/Resources/db.sqlite'); 60 | $config = Setup::createAnnotationMetadataConfiguration(array(__DIR__.'/Fixtures'), true); 61 | $em1 = EntityManager::create($params, $config); 62 | $em2 = EntityManager::create($params, $config); 63 | 64 | // Create a new entity which should be slugified 65 | $persistedArticle = new DoctrineArticle(); 66 | $persistedArticle->setTitle('Hello world!'); 67 | $persistedArticle->slugify($this->defaultSlugGenerator); 68 | 69 | // Store into database slugified entity 70 | $em1->persist($persistedArticle); 71 | $em1->flush(); 72 | 73 | // Retrieve entity from database 74 | $loadedArticle = $em2->find('Ddd\Slug\Tests\Fixtures\DoctrineArticle', $persistedArticle->getId()); 75 | $this->assertEquals('hello-world', $loadedArticle->getSlug()); 76 | 77 | TestDatabase::restore(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Ddd/Mail/Tests/Acceptance/BasicMailTest.php: -------------------------------------------------------------------------------- 1 | mail = new TextMail(new Contact('rouffj@gmail.com')); 18 | } 19 | 20 | public function testWhenNewMail() 21 | { 22 | $mail = new TextMail($from = new Contact('foo@bar.com')); 23 | 24 | $this->assertEquals('utf-8', $mail->getCharset()); 25 | $this->assertNull($mail->getSubject()); 26 | $this->assertNull($mail->getBody()); 27 | $this->assertEquals($from, $mail->getFrom()); 28 | $this->assertFalse($mail->isSent()); 29 | $this->assertEquals(array(), $mail->getFailedRecipients()); 30 | $this->assertEquals(array(), $mail->getRecipients()); 31 | } 32 | 33 | public function testSendWhenMailNotComposed() 34 | { 35 | try { 36 | $this->mail->send(new NullMailer); 37 | $this->fail('An exception should be thrown because neither subject nor body filled in'); 38 | } catch(MailNotComposedException $e) { 39 | $this->assertTrue(true); 40 | } 41 | } 42 | 43 | public function testSendWhenMailComposedWithNullValue() 44 | { 45 | $this->mail->compose(null, null); 46 | 47 | try { 48 | $this->mail->send(new NullMailer); 49 | $this->fail('An exception should be thrown because neither subject nor body filled in'); 50 | } catch(MailNotComposedException $e) { 51 | $this->assertTrue(true); 52 | } 53 | } 54 | 55 | public function testComposeWhenTextGiven() 56 | { 57 | $this->mail->compose('My subject', 'My body'); 58 | 59 | $this->assertEquals('My subject', $this->mail->getSubject()); 60 | $this->assertEquals('My body', $this->mail->getBody()); 61 | } 62 | 63 | public function testSendWhenMailWithoutRecipient() 64 | { 65 | $this->mail->compose('My subject', null); 66 | 67 | try { 68 | $this->mail->send(new NullMailer); 69 | $this->fail('An exception should be thrown because no recipient added'); 70 | } catch(MailWithoutRecipientException $e) { 71 | $this->assertTrue(true); 72 | } 73 | } 74 | 75 | public function testSendWhenMailSent() 76 | { 77 | $this->mail->compose('My subject', null); 78 | $this->mail->addRecipient(new Contact('rouffj@gmail.com')); 79 | 80 | $this->mail->send(new NullMailer); 81 | 82 | $this->assertEquals(array(), $this->mail->getFailedRecipients()); 83 | $this->assertEquals(true, $this->mail->isSent()); 84 | } 85 | 86 | public function testSendWhenMailNotSent() 87 | { 88 | $this->mail->compose('My subject', null); 89 | $this->mail->addRecipient($contact = new Contact('rouffj@gmail.com')); 90 | 91 | $this->mail->send(new NullMailer(false)); 92 | 93 | $this->assertEquals(array($contact), $this->mail->getFailedRecipients()); 94 | $this->assertEquals(false, $this->mail->isSent()); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/Ddd/Mail/README.md: -------------------------------------------------------------------------------- 1 | # Mail # 2 | 3 | 4 | **Mail** is a component which allow to create/send email easily whatever mailer 5 | mecanism you use (SwiftMailer...). 6 | 7 | ## Installation ## 8 | 9 | Using Composer, just require the `ddd/components` package: 10 | 11 | ``` javascript 12 | { 13 | "require": { 14 | "ddd/components": "dev-master" 15 | } 16 | } 17 | ``` 18 | 19 | ## Usage ## 20 | 21 | ### 1. Prepare your email ### 22 | 23 | #### Method A #### 24 | 25 | ```php 26 | compose('[Github] Payment receipt', 'Here my body formatted in Text format') 36 | ->addRecipient(new Contact('customer1@gmail.com')) 37 | ->addRecipient(new Contact('customer2@gmail.com', 'Customer 2')) 38 | ; 39 | ``` 40 | 41 | #### Method B #### 42 | 43 | ```php 44 | compose('[Github] Payment receipt', 'Here my body formatted in Text format') 52 | ->addRecipients(array( 53 | 'customer1@gmail.com', 54 | 'customer2@gmail.com' => 'Customer 2' 55 | )) 56 | ->getTextMail() 57 | ; 58 | ``` 59 | 60 | ### 2. Send it### 61 | 62 | With `Mail` you can send your emails with the mailer of your choice (SwiftMailer, Amazon SES, Compain monitor...): 63 | 64 | ```php 65 | $mail->send(new SwiftMailer($container->get('swift_mailer'))); // Send email with SwiftMailer. 66 | $mail->send(new AmazonSesMailer($container->get('aws.ses.client'))); // Send same email with Amazon SES. 67 | ``` 68 | 69 | Icebox 70 | ------ 71 | 72 | * [x] As a user, I should be able to create a sendable basic email with very simple API. 73 | * [x] As a user, I should be able to send basic `TextMail` with SwiftMailer as `MailerInterface` implementation. 74 | * [x] As a user, I should be able to send basic `TextMail` with "Amazon SES" as `MailerInterface` implementation. 75 | * [ ][Chore] As a user, I'm expecting when any error occured, a `MailerException` should be thrown whatever implementation used. 76 | * [x] As a user, I should be able to create a mail without knowing any domain object. 77 | * [ ] As a user, I could give as recipient a group of contacts that will enable "Newsletter" mode. 78 | * [ ] As a user, I could be able to send basic `HtmlEmail` with SwiftMailer. 79 | * [ ] As a user, I could add attachments to `HtmlEmail` AND `TextEmail`. 80 | * [ ] As a user, I could give copy carbon recipient. 81 | * [ ] As a user, I could give blind copy carbon recipient. 82 | * [ ] As a user, a contact should always be valid. 83 | * [ ] As a user, I should be able to change default UTF-8 encoding. 84 | * [ ] As a user, I should be able to send basic `TextMail` with "Compaign Monitor" as `MailerInterface` implementation. 85 | * [ ] As a user, when I put HTML content as body in a `TextMail` the content should be strip of all HTML tags. 86 | * [ ] As a user, when I put HTML content as body in an `HtmlMail` the plain text version should be generated automatically. 87 | * [ ] As a Amazon SES user, I should be able to put special characters in headers (To:, From: etc.). 88 | 89 | Credits 90 | ------- 91 | 92 | - Joseph Rouff 93 | 94 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/DurationTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(780, $duration->toSeconds()->getValue()); 15 | 16 | $duration = new Duration(2, TimeUnit::hour()); 17 | $this->assertEquals(7200, $duration->toSeconds()->getValue()); 18 | 19 | $duration = new Duration(5, TimeUnit::day()); 20 | $this->assertEquals(432000, $duration->toSeconds()->getValue()); 21 | 22 | $duration = new Duration(1, TimeUnit::week()); 23 | $this->assertEquals(604800, $duration->toSeconds()->getValue()); 24 | 25 | try { 26 | $duration = new Duration(2, TimeUnit::month()); 27 | $duration->toSeconds(); 28 | $this->assertEquals(true, false); 29 | } catch (\LogicException $e) { 30 | $this->assertEquals(true, true); 31 | } 32 | 33 | } 34 | 35 | public function testToMinutes() 36 | { 37 | $duration = new Duration(125, TimeUnit::second()); 38 | $this->assertEquals(2, $duration->toMinutes()->getValue()); 39 | $duration = new Duration(11, TimeUnit::second()); 40 | $this->assertEquals(0, $duration->toMinutes()->getValue()); 41 | 42 | $duration = new Duration(13, TimeUnit::minute()); 43 | $this->assertEquals($duration, $duration->toMinutes()); 44 | 45 | $duration = new Duration(3, TimeUnit::hour()); 46 | $this->assertEquals(180, $duration->toMinutes()->getValue()); 47 | 48 | $duration = new Duration(4, TimeUnit::day()); 49 | $this->assertEquals(5760, $duration->toMinutes()->getValue()); 50 | 51 | $duration = new Duration(2, TimeUnit::week()); 52 | $this->assertEquals(20160, $duration->toMinutes()->getValue()); 53 | 54 | try { 55 | $duration = new Duration(2, TimeUnit::year()); 56 | $duration->toMinutes(); 57 | $this->assertEquals(true, false); 58 | } catch (\LogicException $e) { 59 | $this->assertEquals(true, true); 60 | } 61 | } 62 | 63 | public function testToHours() 64 | { 65 | $duration = new Duration(8200, TimeUnit::second()); 66 | $this->assertEquals(2, $duration->toHours()->getValue()); 67 | $duration = new Duration(100, TimeUnit::second()); 68 | $this->assertEquals(0, $duration->toHours()->getValue()); 69 | 70 | $duration = new Duration(60, TimeUnit::minute()); 71 | $this->assertEquals(1, $duration->toHours()->getValue()); 72 | 73 | $duration = new Duration(3, TimeUnit::hour()); 74 | $this->assertEquals($duration, $duration->toHours()); 75 | 76 | $duration = new Duration(0, TimeUnit::day()); 77 | $this->assertEquals(0, $duration->toHours()->getValue()); 78 | $duration = new Duration(4, TimeUnit::day()); 79 | $this->assertEquals(96, $duration->toHours()->getValue()); 80 | 81 | $duration = new Duration(1, TimeUnit::week()); 82 | $this->assertEquals(168, $duration->toHours()->getValue()); 83 | 84 | try { 85 | $duration = new Duration(2, TimeUnit::year()); 86 | $duration->toMinutes(); 87 | $this->assertEquals(true, false); 88 | } catch (\LogicException $e) { 89 | $this->assertEquals(true, true); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /src/Ddd/Mail/Tests/Acceptance/TextMailTest.php: -------------------------------------------------------------------------------- 1 | mail = new TextMail(new Contact('rouffj@gmail.com')); 19 | } 20 | 21 | public function testWhenSuccessfullySentWithSwiftMailer() 22 | { 23 | $swiftMailer = $this->getMock('Swift_Mailer', array(), array(), '', false); 24 | $this->mail->compose('Subject', 'Here is the body'); 25 | $this->mail->addRecipient(new Contact('foo@bar.com', 'Foo Bar')); 26 | 27 | $swiftMailer->expects($this->once())->method('send'); 28 | $this->mail->send($mailer = new SwiftMailer($swiftMailer)); 29 | 30 | $msg = $mailer->getSentMessage(); 31 | $this->assertEquals('Subject', $msg->getSubject()); 32 | $this->assertEquals('Here is the body', $msg->getBody()); 33 | $this->assertEquals(array('foo@bar.com' => 'Foo Bar'), $msg->getTo()); 34 | $this->assertEquals(array('rouffj@gmail.com' => null), $msg->getFrom()); 35 | $this->assertEquals('text/plain', $msg->getContentType()); 36 | $this->assertEquals('utf-8', $msg->getCharset()); 37 | $this->assertEquals(array(), $this->mail->getFailedRecipients()); 38 | } 39 | 40 | public function testWhenSuccessfullySentWithSesAmazon() 41 | { 42 | $amazonMailer = $this->getMock('Aws\Ses\SesClient', array(), array(), '', false); 43 | $command = $this->getMock('Guzzle\Service\Command\CommandInterface', array(), array(), '', false); 44 | $this->mail->compose('Subject', 'Here is the body'); 45 | $this->mail->addRecipient(new Contact('foo@bar.com', 'Foo Bar')); 46 | 47 | $command->expects($this->once())->method('execute'); 48 | $amazonMailer->expects($this->once())->method('getCommand')->will($this->returnValue($command)); 49 | $this->mail->send($mailer = new AmazonSesMailer($amazonMailer)); 50 | 51 | $msg = $mailer->getSentMessage(); 52 | $this->assertEquals($this->mail->getSubject(), $msg['Message']['Subject']['Data']); 53 | $this->assertEquals($this->mail->getBody(), $msg['Message']['Body']['Text']['Data']); 54 | $this->assertEquals($this->mail->getFrom()->toString(), $msg['Source']); 55 | $this->assertEquals(array('foo@bar.com'), $msg['Destination']['ToAddresses']); 56 | $this->assertEquals('utf-8', $msg['Message']['Subject']['Charset']); 57 | $this->assertEquals('utf-8', $msg['Message']['Body']['Text']['Charset']); 58 | } 59 | 60 | public function testWhenFailedSentWithSwiftMailer() 61 | { 62 | $swiftMailer = $this->getMock('Swift_Mailer', array(), array(), '', false); 63 | $this->mail->compose('Subject', null); 64 | $this->mail->addRecipient(new Contact('foo@bar.com', 'Foo Bar')); 65 | 66 | $swiftMailer->expects($this->once())->method('send')->will($this->returnCallback(function($message, &$failedRecipients) { 67 | $failedRecipients = array('foo@bar.com'); 68 | })); 69 | $this->mail->send($mailer = new SwiftMailer($swiftMailer)); 70 | 71 | $msg = $mailer->getSentMessage(); 72 | $this->assertEquals(array(new Contact('foo@bar.com')), $this->mail->getFailedRecipients()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/Ddd/Time/README.md: -------------------------------------------------------------------------------- 1 | TimeMachine 2 | =========== 3 | 4 | Installation 5 | ------------ 6 | 7 | Using Composer, just require the `ddd/time` package: 8 | 9 | ``` javascript 10 | { 11 | "require": { 12 | "ddd/time": "dev-master" 13 | } 14 | } 15 | ``` 16 | 17 | Howtos 18 | ------ 19 | 20 | ``` 21 | Ddd\Time\Tests\HowTo\DateInterval 22 | [x] How to get number of days between 2 dates 23 | [ ] How to get number of hours between 2 dates 24 | [ ] How to get number of minutes between 2 dates 25 | [ ] How to get number of seconds between 2 dates 26 | [x] How to get each day between 2 dates 27 | [x] How to know if a date interval is before after during other date interval 28 | [ ] How to know if a date interval is before after during a given date 29 | [x] How to know if a date interval is before after during a given time interval 30 | [ ] How to know if a date interval is before after during a given time point 31 | [ ] How to tranform date interval into time interval 32 | 33 | Ddd\Time\Tests\HowTo\Date 34 | [x] How to create a date only 35 | [x] How to come back at begin of current week 36 | [x] How to know if a date is after before equal to an other 37 | [x] How to convert a ddd time date object into regular date time object 38 | [x] How to know if date is during weekend or weekday 39 | [x] How to get previous next date 40 | [x] How to add remove a duration from it in days 41 | [ ] How to add remove a duration from it in years months weeks 42 | [ ] How to add remove a duration from it in hours minutes seconds 43 | [x] How to add remove a composite duration 44 | [x] How to transform a date into a time point 45 | [x] How to know diff between it and an other date 46 | [ ] How to know diff between it and a time point 47 | [x] How to know if date is before during after a date interval 48 | 49 | Ddd\Time\Tests\HowTo\Duration 50 | [x] How to know how long x days in hours minutes seconds 51 | [x] How to know how long x weeks in days hours minutes seconds 52 | [x] How to know how long x months in weeks days hours minutes seconds 53 | [x] How to know how long x years in months weeks days hours minutes seconds 54 | [ ] How to know how long a years b months c weeks d days in hours minutes seconds 55 | 56 | Ddd\Time\Tests\HowTo\TimeInterval 57 | [ ] How to know if a time interval is before after during an other time interval 58 | [ ] How to know if a time interval is before after during a given date interval 59 | [ ] How to know if a time interval is before after during a given date 60 | [ ] How to know if a time interval is before after during a given date time 61 | [ ] How to transform a time interval into a date interval destroy data 62 | [ ] How to know how long a time interval are in at least seconds minutes hours days weeks years 63 | [x] How to transform string representation of time interval into an object 64 | 65 | Ddd\Time\Tests\HowTo\TimeOfDay 66 | [x] How to know if a time of day is before after equal an other time of day 67 | [x] How to know if it is the ante meridian post meridian 68 | 69 | Ddd\Time\Tests\HowTo\TimePoint 70 | [x] How to know if it is before after equal an other time point 71 | [x] How to know if it is before after equal a given date 72 | [x] How to know if it is before after during a given date interval 73 | [x] How to know if it is before after equals a given time interval 74 | [x] How to know if it is during night or daylight 75 | [x] How to add remove duration from it 76 | [x] How to convert a ddd time point object into regular date timeobject 77 | [x] How to know if time point is before during after a time interval 78 | ``` 79 | 80 | Credits 81 | ------- 82 | 83 | - Joseph Rouff 84 | - Inspired by http://timeandmoney.sourceforge.net/timealgebra.html 85 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/Model/TimeIntervalTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($expectedDuration, $interval->getLength()); 21 | } 22 | 23 | public function testIsBefore() 24 | { 25 | $interval = TimeIntervalFactory::create('2012-01-01 20:00', '2012-01-01 21:59'); 26 | $intervalA = TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 19:59'); // is before 27 | $intervalB = TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 20:10'); // is not before 28 | 29 | $this->assertFalse($interval->isBefore($intervalA)); 30 | $this->assertTrue($intervalA->isBefore($interval)); 31 | $this->assertFalse($intervalB->isBefore($interval)); 32 | $this->assertFalse($interval->isBefore($intervalB)); 33 | //TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 20:00'); // is before 34 | //TimeIntervalFactory::create('2012-01-01 22:00', '2012-01-01 22:30'); // is after 35 | //TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 21:30'); // is during 36 | //TimeIntervalFactory::create('2012-01-01 21:30', '2012-01-01 22:30'); // is during 37 | //TimeIntervalFactory::create('2012-01-01 15:00', '2012-01-01 23:00'); // is during? 38 | } 39 | 40 | public function testIsAfter() 41 | { 42 | $interval = TimeIntervalFactory::create('2012-01-01 20:00', '2012-01-01 21:59'); 43 | $intervalA = TimeIntervalFactory::create('2012-01-01 22:00', '2012-01-01 22:30'); // is after 44 | 45 | $this->assertFalse($interval->isAfter($intervalA)); 46 | $this->assertTrue($intervalA->isAfter($interval)); 47 | } 48 | 49 | public function testIsDuring() 50 | { 51 | $interval = TimeIntervalFactory::create('2012-01-01 20:00', '2012-01-01 21:59'); 52 | $intervalA = TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 21:30'); // is during 53 | $intervalB = TimeIntervalFactory::create('2012-01-01 21:30', '2012-01-01 22:30'); // is during 54 | $intervalC = TimeIntervalFactory::create('2012-01-01 15:00', '2012-01-01 23:00'); // is during? 55 | 56 | $this->assertTrue($interval->isDuring($intervalA)); 57 | $this->assertTrue($intervalA->isDuring($interval)); 58 | 59 | $this->assertTrue($interval->isDuring($intervalB)); 60 | $this->assertTrue($intervalB->isDuring($interval)); 61 | 62 | $this->assertTrue($interval->isDuring($intervalC)); 63 | $this->assertTrue($intervalC->isDuring($interval)); 64 | } 65 | 66 | public function testIsInclude() 67 | { 68 | $interval = TimeIntervalFactory::create('2013-01-13 01:00', '2013-01-14 18:30'); 69 | 70 | $this->markTestIncomplete('Method should be implemented'); 71 | $this->assertTrue($interval->isInclude(TimeIntervalFactory::create('2013-01-13 00:59', '2013-01-14 18:30'))); 72 | $this->assertTrue($interval->isInclude($interval)); 73 | $this->assertTrue($interval->isInclude(TimeIntervalFactory::create('2013-01-13 01:00', '2013-01-14 18:31'))); 74 | $this->assertTrue($interval->isInclude(DateIntervalFactory::create('2013-01-13', '2013-01-14'))); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/DateInterval.php: -------------------------------------------------------------------------------- 1 | isBefore($begin)) { 14 | throw new \Exception('DateInterval: the begin date must be before the end date.'); 15 | } 16 | 17 | $this->begin = $begin; 18 | $this->end = $end; 19 | $this->current = $this->begin; 20 | } 21 | 22 | public function nextDate() 23 | { 24 | $this->current = $this->current->next(); 25 | 26 | return !$this->current->isAfter($this->end); 27 | } 28 | 29 | public function getCurrent() 30 | { 31 | return $this->current; 32 | } 33 | 34 | /** 35 | * Get duration in days separating the begin and end date of DateInterval. 36 | * 37 | * @return Duration Expressed in days. 38 | */ 39 | public function getDuration() 40 | { 41 | return $this->begin->diff($this->end); 42 | } 43 | 44 | /** 45 | * Gets the begin value 46 | * 47 | * @return Date 48 | */ 49 | public function getBegin() 50 | { 51 | return $this->begin; 52 | } 53 | 54 | /** 55 | * Gets the end value 56 | * 57 | * @return Date 58 | */ 59 | public function getEnd() 60 | { 61 | return $this->end; 62 | } 63 | 64 | /** 65 | * @param IntervalInterface $other 66 | * @return bool 67 | */ 68 | public function isBefore(IntervalInterface $other) 69 | { 70 | $begin = ($other instanceof TimeInterval) ? $other->getBegin()->getDate() : $other->getBegin(); 71 | $end = ($other instanceof TimeInterval) ? $other->getEnd()->getDate() : $other->getEnd(); 72 | 73 | return $this->begin->isBefore($begin) && $this->begin->isBefore($end); 74 | } 75 | 76 | /** 77 | * @param IntervalInterface $other 78 | * @return bool 79 | */ 80 | public function isAfter(IntervalInterface $other) 81 | { 82 | $begin = ($other instanceof TimeInterval) ? $other->getBegin()->getDate() : $other->getBegin(); 83 | $end = ($other instanceof TimeInterval) ? $other->getEnd()->getDate() : $other->getEnd(); 84 | 85 | return $this->begin->isAfter($begin) && $this->begin->isAfter($end); 86 | } 87 | 88 | /** 89 | * @param IntervalInterface $other 90 | * @return bool 91 | */ 92 | public function isDuring(IntervalInterface $other) 93 | { 94 | $begin = $this->begin->toDateTime(); 95 | $end = $this->end->toDateTime(); 96 | 97 | return 98 | $begin === max($begin, $other->getBegin()->toDateTime()) && 99 | $end === min($end, $other->getEnd()->toDateTime()) 100 | ; 101 | } 102 | 103 | public function isPartiallyBefore(IntervalInterface $interval) 104 | { 105 | throw new \Exception('Not implemented'); 106 | } 107 | 108 | public function isPartiallyAfter(IntervalInterface $interval) 109 | { 110 | throw new \Exception('Not implemented'); 111 | } 112 | 113 | public function isInclude(IntervalInterface $other) 114 | { 115 | $otherBegin = ($other instanceof TimeInterval) ? $other->getBegin()->getDate() : $other->getBegin(); 116 | $otherEnd = ($other instanceof TimeInterval) ? $other->getEnd()->getDate() : $other->getEnd(); 117 | 118 | return 119 | ($this->begin->isBefore($otherBegin) || $this->begin->isEquals($otherBegin)) && 120 | ($this->end->isAfter($otherEnd) || $this->end->isEquals($otherEnd)) 121 | ; 122 | } 123 | } 124 | 125 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/DateIntervalTest.php: -------------------------------------------------------------------------------- 1 | getDuration(); 18 | 19 | $this->assertEquals(new Duration(19, TimeUnit::day()), $duration); 20 | } 21 | 22 | public function testHowToGetNumberOfHoursBetween2Dates() 23 | { 24 | $interval = new DateInterval(new Date(2013, 1, 1), new Date(2013, 1, 3)); 25 | $duration = $interval->getDuration(); 26 | 27 | $this->assertEquals(new Duration(48, TimeUnit::hour()), $duration->toHours()); // 2 days 28 | } 29 | 30 | public function testHowToGetNumberOfMinutesBetween2Dates() 31 | { 32 | $interval = new DateInterval(new Date(2013, 1, 1), new Date(2013, 1, 3)); 33 | $duration = $interval->getDuration(); 34 | 35 | $this->assertEquals(new Duration(60*24*2, TimeUnit::minute()), $duration->toMinutes()); // 2 days 36 | } 37 | 38 | public function testHowToGetNumberOfSecondsBetween2Dates() 39 | { 40 | $interval = new DateInterval(new Date(2013, 1, 1), new Date(2013, 1, 2)); 41 | $duration = $interval->getDuration(); 42 | 43 | $this->assertEquals(new Duration(60*60*24, TimeUnit::second()), $duration->toSeconds()); // 1 day 44 | } 45 | 46 | public function testHowToGetEachDayBetween2Dates() 47 | { 48 | $interval = new DateInterval(new Date(2013, 1, 1), new Date(2013, 1, 2)); 49 | $duration = $interval->getDuration(); 50 | $dates = array(); 51 | do { 52 | $nextDate = $interval->getCurrent(); 53 | $dates[] = $nextDate; 54 | } while ($interval->nextDate()); 55 | 56 | $this->assertEquals(array(new Date(2013, 1, 1), new Date(2013, 1, 2)), $dates); 57 | } 58 | 59 | public function testHowToKnowIfADateIntervalIsBeforeAfterDuringOtherDateInterval() 60 | { 61 | $interval = new DateInterval(new Date(2013, 6, 1), new Date(2013, 6, 15)); 62 | $before = new DateInterval(new Date(2013, 5, 20), new Date(2013, 5, 30)); 63 | $after = new DateInterval(new Date(2013, 6, 16), new Date(2013, 6, 20)); 64 | $during = new DateInterval(new Date(2013, 5, 1), new Date(2013, 6, 30)); 65 | $partiallyDuring = new DateInterval(new Date(2013, 1, 1), new Date(2013, 6, 10)); 66 | 67 | $this->assertTrue($interval->isBefore($after)); 68 | $this->assertTrue($interval->isAfter($before)); 69 | $this->assertTrue($interval->isDuring($during)); 70 | $this->assertFalse($interval->isDuring($partiallyDuring)); 71 | } 72 | 73 | public function testHowToKnowIfADateIntervalIsBeforeAfterDuringAGivenDate() 74 | { 75 | $this->markTestIncomplete(); 76 | } 77 | 78 | public function testHowToKnowIfADateIntervalIsBeforeAfterDuringAGivenTimeInterval() 79 | { 80 | $jan10to20 = new DateInterval(new Date(2013, 1, 10), new Date(2013, 1, 20)); 81 | $timeInterval = TimeIntervalFactory::create('2013-01-01 10:00', '2013-01-21 20:00'); 82 | 83 | $this->assertFalse($jan10to20->isBefore($timeInterval)); 84 | $this->assertTrue($jan10to20->isDuring($timeInterval)); 85 | $this->assertFalse($jan10to20->isAfter($timeInterval)); 86 | } 87 | 88 | public function testHowToKnowIfADateIntervalIsBeforeAfterDuringAGivenTimePoint() 89 | { 90 | $this->markTestIncomplete(); 91 | } 92 | 93 | public function testHowToTranformDateIntervalIntoTimeInterval() 94 | { 95 | $this->markTestIncomplete(); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/Date.php: -------------------------------------------------------------------------------- 1 | day = (int) $day; 17 | $this->month = (int) $month; 18 | $this->year = (int) $year; 19 | } 20 | 21 | public function during(Duration $duration) 22 | { 23 | $begin = new TimePoint($this->year, $this->month, $this->day, 0, 0); 24 | $end = $begin->plus($duration); 25 | 26 | return new DateInterval($begin->getDate(), $end->getDate()); 27 | } 28 | 29 | public function minus(Duration $duration) 30 | { 31 | return $this->toTimePoint()->minus($duration)->getDate(); 32 | } 33 | 34 | public function plus(Duration $duration) 35 | { 36 | return $this->toTimePoint()->plus($duration)->getDate(); 37 | } 38 | 39 | public function isAfter(Date $date) 40 | { 41 | return 42 | $this->year > $date->getYear() || 43 | ($this->year >= $date->getYear() && $this->month > $date->getMonth()) || 44 | ($this->year >= $date->getYear() && $this->month >= $date->getMonth() && $this->day > $date->getDay()) 45 | ; 46 | } 47 | 48 | public function diff(Date $date) 49 | { 50 | return new Duration($this->toDateTime()->diff($date->toDateTime())->d, TimeUnit::day()); 51 | } 52 | 53 | public function isBefore(Date $date) 54 | { 55 | return 56 | false === $this->isAfter($date) && 57 | false === $this->isEquals($date) 58 | ; 59 | } 60 | 61 | public function isEquals(Date $date) 62 | { 63 | return 64 | $this->year === $date->getYear() && 65 | $this->month === $date->getMonth() && 66 | $this->day === $date->getDay() 67 | ; 68 | } 69 | 70 | public function beginOfWeek() 71 | { 72 | $i = 0; 73 | $curDate = $this; 74 | while ($i < 8) { 75 | $dtime = $curDate->toDateTime(); 76 | $numOfWeek = (int) $dtime->format('N'); 77 | if (1 === $numOfWeek) { 78 | return $curDate; 79 | } 80 | $curDate = $curDate->previous(); 81 | $i = $i + 1; 82 | } 83 | throw new \RunTimeException('Loop error with begin of week'); 84 | } 85 | 86 | public function next() 87 | { 88 | return $this->plus(new Duration(1, TimeUnit::day())); 89 | } 90 | 91 | public function previous() 92 | { 93 | return $this->minus(new Duration(1, TimeUnit::day())); 94 | } 95 | 96 | public function toDateTime() 97 | { 98 | $dateTime = new \Datetime(); 99 | $dateTime->setDate($this->year, $this->month, $this->day); 100 | $dateTime->setTime(0, 0, 0); 101 | 102 | return $dateTime; 103 | } 104 | 105 | public function toTimePoint() 106 | { 107 | return new TimePoint($this->year, $this->month, $this->day, null, null); 108 | } 109 | 110 | public function toDateInterval() 111 | { 112 | return new DateInterval($this, $this); 113 | } 114 | 115 | public function isWeekDay() 116 | { 117 | return !$this->isWeekEndDay(); 118 | } 119 | 120 | public function isWeekEndDay() 121 | { 122 | return intval($this->toDateTime()->format('w')) === self::SUNDAY || intval($this->toDateTime()->format('w')) === self::SATURDAY; 123 | } 124 | 125 | /** 126 | * Gets the value of year 127 | * 128 | * @return int 129 | */ 130 | public function getYear() 131 | { 132 | return $this->year; 133 | } 134 | 135 | /** 136 | * Gets the value of month 137 | * 138 | * @return int 139 | */ 140 | public function getMonth() 141 | { 142 | return $this->month; 143 | } 144 | 145 | /** 146 | * Gets the value of day 147 | * 148 | * @return int 149 | */ 150 | public function getDay() 151 | { 152 | return $this->day; 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/TimePointTest.php: -------------------------------------------------------------------------------- 1 | assertEquals($second->isAfter($first), true); 24 | $this->assertEquals($second->isBefore($third), false); 25 | $this->assertEquals($first->isAfter($second), false); 26 | $this->assertEquals($third->isEquals($second), true); 27 | } 28 | 29 | public function testHowToKnowIfItIsBeforeAfterEqualAGivenDate() 30 | { 31 | $timePoint = new TimePoint(2013, 3, 12, 18, 27); 32 | $dateBefore = new Date(2013, 1, 1); 33 | $dateAfter = new Date(2013, 8, 15); 34 | $dateEqual = new Date(2013, 3, 12); 35 | $this->assertEquals(true, $dateBefore->isBefore($timePoint->getDate())); 36 | $this->assertEquals(true, $dateAfter->isAfter($timePoint->getDate())); 37 | $this->assertEquals(true, $dateEqual->isEquals($timePoint->getDate())); 38 | } 39 | 40 | public function testHowToKnowIfItIsBeforeAfterDuringAGivenDateInterval() 41 | { 42 | $timePoint = new TimePoint(2013, 3, 1, 18, 27); 43 | $dateInterval = new DateInterval(new Date(2013, 1, 1), new Date(2013, 1, 15)); 44 | 45 | $this->assertEquals(true, $dateInterval->isBefore($timePoint->getDate()->toDateInterval())); 46 | $this->assertEquals(false, $dateInterval->isAfter($timePoint->getDate()->toDateInterval())); 47 | $this->assertEquals(false, $dateInterval->isDuring($timePoint->getDate()->toDateInterval())); 48 | } 49 | 50 | public function testHowToKnowIfItIsBeforeAfterEqualsAGivenTimeInterval() 51 | { 52 | $timePoint = new TimePoint(2013, 3, 1, 18, 27); 53 | $timeInterval = new TimeInterval(new TimePoint(2013, 1, 1, 0, 30), new TimePoint(2013, 1, 15, 23, 30)); 54 | 55 | $this->assertEquals(true, $timeInterval->isBefore($timePoint->toTimeInterval())); 56 | $this->assertEquals(false, $timeInterval->isAfter($timePoint->toTimeInterval())); 57 | $this->assertEquals(false, $timeInterval->isDuring($timePoint->toTimeInterval())); 58 | } 59 | 60 | public function testHowToKnowIfItIsDuringNightOrDaylight() 61 | { 62 | $nightTimePoint = new TimePoint(2013, 3, 12, 3, 30); 63 | $dayTimePoint = new TimePoint(2013, 3, 12, 15, 30); 64 | 65 | // Using the Eiffel Tower's coordinates 66 | $this->assertTrue($nightTimePoint->isNightTime(48.8582, 2.2945)); 67 | $this->assertFalse($dayTimePoint->isNightTime(48.8582, 2.2945)); 68 | } 69 | 70 | public function testHowToAddRemoveDurationFromIt() 71 | { 72 | $startTimePoint = new TimePoint(2013, 3, 12, 18, 27); 73 | $stopTimePoint = new TimePoint(2013, 3, 14, 18, 27); 74 | $duration = new Duration(2, TimeUnit::day()); 75 | $result = $startTimePoint->plus($duration); 76 | $this->assertEquals($result, $stopTimePoint); 77 | } 78 | 79 | public function testHowToConvertADddTimePointObjectIntoRegularDateTimeobject() 80 | { 81 | $timepoint = new TimePoint(2013, 3, 12, 18, 27, 11); 82 | $datetime = new \DateTime(); 83 | $datetime->setDate(2013, 3, 12); 84 | $datetime->setTime(18, 27, 11); 85 | $this->assertEquals($timepoint->toDateTime(), $datetime); 86 | } 87 | 88 | public function testHowToKnowIfTimePointIsBeforeDuringAfterATimeInterval() 89 | { 90 | $doctorAppointment = new TimePoint(2013, 1, 5, 10, 0); 91 | $doctorAppointment = $doctorAppointment->toTimeInterval(); 92 | $samBrithdayParty = TimeIntervalFactory::create('2013-01-05 11:30', '2013-01-05 13:00'); 93 | $sportSession = TimeIntervalFactory::create('2013-01-05 09:00', '2013-01-05 10:30'); 94 | 95 | $this->assertTrue($doctorAppointment->isBefore($samBrithdayParty)); 96 | $this->assertTrue($doctorAppointment->isDuring($sportSession)); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/TimePoint.php: -------------------------------------------------------------------------------- 1 | date = new Date($year, $month, $day); 15 | $this->time = new TimeOfDay($hour, $minute, $second); 16 | } 17 | 18 | public function during(Duration $duration) 19 | { 20 | $interval = $this->plus($duration); 21 | 22 | return new TimeInterval($this, $interval); 23 | } 24 | 25 | public function until(TimePoint $point) 26 | { 27 | return new TimeInterval($this, $point); 28 | } 29 | 30 | public function plus(Duration $duration) 31 | { 32 | $date = $this->toDateTime(); 33 | $date->add($duration->asPHPDateInterval()); 34 | 35 | return TimePointFactory::fromDateTime($date); 36 | } 37 | 38 | public function minus(Duration $duration) 39 | { 40 | $date = $this->toDateTime(); 41 | $date->sub($duration->asPHPDateInterval()); 42 | 43 | return TimePointFactory::fromDateTime($date); 44 | } 45 | 46 | public function isAfter(TimePoint $point) 47 | { 48 | if ($this->date->isEquals($point->getDate())) { 49 | if ($this->time->isAfter($point->getTimeOfDay())){ 50 | return true; 51 | } 52 | } else if ($this->date->isAfter($point->getDate())) { 53 | return true; 54 | } 55 | 56 | return false; 57 | } 58 | 59 | public function isBefore(TimePoint $other) 60 | { 61 | return 62 | !$this->isAfter($other) && 63 | !$this->isEquals($other); 64 | } 65 | 66 | public function isEquals(TimePoint $point) 67 | { 68 | return 69 | $this->date->isEquals($point->getDate()) && 70 | $this->time->isEquals($point->getTimeOfDay()) 71 | ; 72 | } 73 | 74 | /** 75 | * Gets the value of year 76 | * 77 | * @return int 78 | */ 79 | public function getYear() 80 | { 81 | return $this->date->getYear(); 82 | } 83 | 84 | /** 85 | * Gets the value of month 86 | * 87 | * @return int 88 | */ 89 | public function getMonth() 90 | { 91 | return $this->date->getMonth(); 92 | } 93 | 94 | /** 95 | * Gets the value of day 96 | * 97 | * @return int 98 | */ 99 | public function getDay() 100 | { 101 | return $this->date->getDay();; 102 | } 103 | 104 | public function getHour() 105 | { 106 | return $this->time->getHour(); 107 | } 108 | 109 | public function getMinutes() 110 | { 111 | return $this->time->getMinutes(); 112 | } 113 | 114 | public function getSeconds() 115 | { 116 | return $this->time->getSeconds(); 117 | } 118 | 119 | public function toDateTime() 120 | { 121 | $dtime = $this->date->toDateTime(); 122 | $dtime->setTime($this->time->getHour(), $this->time->getMinutes(), $this->time->getSeconds()); 123 | 124 | return $dtime; 125 | } 126 | 127 | public function toTimeInterval() 128 | { 129 | return new TimeInterval($this, $this); 130 | } 131 | 132 | public function getDate() 133 | { 134 | return $this->date; 135 | } 136 | 137 | public function getTimeOfDay() 138 | { 139 | return $this->time; 140 | } 141 | 142 | public function isNightTime($latitude, $longitude) 143 | { 144 | $yesterdaySunset = date_sunset($this->date->previous()->toDateTime()->getTimestamp(), SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude); 145 | $todaySunrise = date_sunrise($this->date->toDateTime()->getTimestamp(), SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude); 146 | 147 | if (false === $yesterdaySunset || false === $todaySunrise) { 148 | throw new \RuntimeException('PHP could not determine the sun information.'); 149 | } 150 | 151 | return ($this->isAfter(TimePointFactory::fromTimestamp($yesterdaySunset)) 152 | && $this->isBefore(TimePointFactory::fromTimestamp($todaySunrise))); 153 | } 154 | 155 | public function __toString() 156 | { 157 | return strtr('{year}/{month}/{day} at {time}', array( 158 | '{year}' => $this->date->getYear(), 159 | '{month}' => $this->date->getMonth(), 160 | '{day}' => $this->date->getDay(), 161 | '{time}' => $this->time, 162 | )); 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /src/Ddd/Time/Tests/HowTo/DateTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf('Ddd\Time\Model\Date', $date); 19 | } 20 | 21 | public function testHowToComeBackAtBeginOfCurrentWeek() 22 | { 23 | $friday = new Date(2013, 1, 4); 24 | $monday = $friday->beginOfWeek(); 25 | 26 | $this->assertEquals(new Date(2012, 12, 31), $monday); 27 | } 28 | 29 | public function testHowToKnowIfADateIsAfterBeforeEqualToAnOther() 30 | { 31 | $jan1 = new Date(2013, 1, 1); 32 | 33 | $this->assertTrue($jan1->isBefore(new Date(2013, 1, 2))); 34 | $this->assertTrue($jan1->isAfter(new Date(2012, 12, 31))); 35 | $this->assertTrue($jan1->isEquals($jan1)); 36 | } 37 | 38 | /** 39 | * Usecases: 40 | * - I want to display a date in custom format in templates. 41 | * 42 | */ 43 | public function testHowToConvertADddTimeDateObjectIntoRegularDateTimeObject() 44 | { 45 | $jan1 = new Date(2013, 1, 1); 46 | 47 | $this->assertEquals(new \DateTime('2013-01-01 00:00:00'), $jan1->toDateTime()); 48 | } 49 | 50 | public function testHowToKnowIfDateIsDuringWeekendOrWeekday() 51 | { 52 | $tuesday = new Date(2013, 1, 1); 53 | $saturday = $tuesday->plus(new Duration(4, TimeUnit::day())); 54 | 55 | $this->assertFalse($tuesday->isWeekEndDay()); 56 | $this->assertTrue($tuesday->isWeekDay()); 57 | $this->assertTrue($saturday->isWeekEndDay()); 58 | $this->assertFalse($saturday->isWeekDay()); 59 | } 60 | 61 | public function testHowToGetPreviousNextDate() 62 | { 63 | $jan1 = new Date(2013, 1, 1); 64 | $dec31 = $jan1->previous(); 65 | $jan2 = $jan1->next(); 66 | 67 | $this->assertEquals(new Date(2012, 12, 31), $dec31); 68 | $this->assertEquals(new Date(2013, 1, 2), $jan2); 69 | } 70 | 71 | public function testHowToAddRemoveADurationFromItInDays() 72 | { 73 | $jan1 = new Date(2013, 1, 1); 74 | $dec31 = $jan1->minus(new Duration(1, TimeUnit::day())); 75 | $jan3 = $jan1->plus(new Duration(2, TimeUnit::day())); 76 | 77 | $this->assertEquals(new Date(2012, 12, 31), $dec31); 78 | $this->assertEquals(new Date(2013, 1, 3), $jan3); 79 | } 80 | 81 | public function testHowToAddRemoveADurationFromItInYearsMonthsWeeks() 82 | { 83 | $this->markTestIncomplete(); 84 | } 85 | 86 | public function testHowToAddRemoveADurationFromItInHoursMinutesSeconds() 87 | { 88 | $this->markTestIncomplete(); 89 | } 90 | 91 | /** 92 | * eg. Allow to add/remove 2 days, 5 hours and 42 minutes easily. 93 | */ 94 | public function testHowToAddRemoveACompositeDuration() 95 | { 96 | } 97 | 98 | public function testHowToTransformADateIntoATimePoint() 99 | { 100 | $jan1 = new Date(2013, 1, 1); 101 | $timePoint = $jan1->toTimePoint(); 102 | 103 | $this->assertInstanceOf('Ddd\Time\Model\TimePoint', $timePoint); 104 | $this->assertEquals($timePoint->getYear(), 2013); 105 | $this->assertEquals($timePoint->getMonth(), 1); 106 | $this->assertEquals($timePoint->getDay(), 1); 107 | $this->assertEquals($timePoint->getHour(), 0); 108 | $this->assertEquals($timePoint->getMinutes(), 0); 109 | $this->assertEquals($timePoint->getSeconds(), 0); 110 | } 111 | 112 | /** 113 | * Use cases : 114 | * - Calculate difference between 2 days 115 | * - Fetch the position of a date from another 116 | * - How many days form my birthday 117 | * 118 | * Returns a Duration Class @see Ddd\Time\Model\Duration. 119 | * 120 | */ 121 | public function testHowToKnowDiffBetweenItAndAnOtherDate() 122 | { 123 | $jan1 = new Date(2013, 1, 1); 124 | $jan10 = new Date(2013, 1, 10); 125 | $diff = $jan1->diff($jan10); 126 | 127 | $this->assertInstanceOf('Ddd\Time\Model\Duration', $diff); 128 | $this->assertEquals($diff, new Duration(9, TimeUnit::day())); 129 | } 130 | 131 | public function testHowToKnowDiffBetweenItAndATimePoint() 132 | { 133 | $this->markTestIncomplete('Should return a composite duration'); 134 | } 135 | 136 | public function testHowToKnowIfDateIsBeforeDuringAfterADateInterval() 137 | { 138 | $winterHolidays2013 = DateIntervalFactory::create('2012-12-20', '2013-01-05'); 139 | $dadVisit = new Date(2012, 12, 29); 140 | $dadVisit = $dadVisit->toDateInterval(); 141 | 142 | $this->assertTrue($dadVisit->isDuring($winterHolidays2013)); 143 | $this->assertFalse($dadVisit->isBefore($winterHolidays2013)); 144 | $this->assertFalse($dadVisit->isAfter($winterHolidays2013)); 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Tests/Model/CalendarTest.php: -------------------------------------------------------------------------------- 1 | calendar = new Calendar('foo calendar', array( 27 | new Event(TimeIntervalFactory::create('2012-01-15 16:00', '2012-01-15 18:30')), 28 | new Event(TimeIntervalFactory::create('2012-01-20 08:00', '2012-01-23 08:00')), 29 | )); 30 | } 31 | 32 | public function testConstructor() 33 | { 34 | $this->assertCount(2, $this->calendar); 35 | foreach ($this->calendar as $event) { 36 | $this->assertTrue($event instanceof EventInterface); 37 | } 38 | } 39 | 40 | public function testDefaultCursor() 41 | { 42 | $cursor = new TimePoint(2012, 1, 15, 16, 0); 43 | $this->assertEquals($cursor, $this->calendar->getCursor()); 44 | } 45 | 46 | public function testCursorFiltering() 47 | { 48 | $this->calendar->setCursor(new TimePoint(2012, 1, 15, 15, 59)); 49 | $this->assertSame(2, $this->calendar->countRemaining()); 50 | 51 | $this->calendar->setCursor(new TimePoint(2012, 1, 17, 0, 0)); 52 | $this->assertSame(1, $this->calendar->countRemaining()); 53 | 54 | $this->calendar->setCursor(new TimePoint(2012, 1, 23, 8, 1)); 55 | $this->assertSame(0, $this->calendar->countRemaining()); 56 | } 57 | 58 | public function testBetween() 59 | { 60 | $this->assertCount(0, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 1, 0, 0), new TimePoint(2012, 1, 15, 15, 59, 59)))); 61 | $this->assertCount(1, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 1, 0, 0), new TimePoint(2012, 1, 15, 16, 1, 0)))); 62 | 63 | $this->assertCount(0, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 23, 8, 1, 0), new TimePoint(2012, 2, 0, 0, 0)))); 64 | $this->assertCount(1, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 20, 7, 59, 59), new TimePoint(2012, 2, 0, 0, 0)))); 65 | 66 | $this->assertCount(0, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 15, 18, 31, 0), new TimePoint(2012, 1, 20, 7, 59, 59)))); 67 | $this->assertCount(2, $this->calendar->between(new TimeInterval(new TimePoint(2012, 1, 15, 18, 29, 59), new TimePoint(2012, 1, 20, 8, 0, 1)))); 68 | } 69 | 70 | public function testAdd() 71 | { 72 | $this->assertCount(2, $this->calendar); 73 | 74 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-01 20:00', '2012-01-01 21:59'))); 75 | $this->assertCount(3, $this->calendar); 76 | 77 | // AllowOverlapStrategy 78 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 19:59'))); 79 | $this->assertCount(4, $this->calendar); 80 | $this->assertCount(2, $this->calendar->between(TimeIntervalFactory::create('2012-01-01 19:30', '2012-01-01 21:30'))); 81 | } 82 | 83 | public function testUpdate() 84 | { 85 | $originalEvent = current(iterator_to_array($this->calendar)); 86 | $updatedEvent = new Event(TimeIntervalFactory::create('2012-01-15 17:00', '2012-01-15 19:30')); 87 | $this->calendar->update($originalEvent, $updatedEvent); 88 | 89 | $this->assertCount(2, $this->calendar); 90 | $this->assertSame($updatedEvent, current(iterator_to_array($this->calendar))); 91 | } 92 | 93 | public function testGroup() 94 | { 95 | $cal = new Calendar('my calendar'); 96 | $cal->add(new Event(TimeIntervalFactory::create('2012-01-01 01:00', '2012-01-01 10:00'))); 97 | $cal->add(new Event(TimeIntervalFactory::create('2012-01-03 01:01', '2012-01-03 10:00'))); 98 | 99 | $cal->group(new Duration(1, TimeUnit::day())); 100 | $this->assertCount(3, $cal->getCalendars()); 101 | } 102 | 103 | public function testAddWithNoOverlapStrategy() 104 | { 105 | $this->calendar->setStrategy(new NoOverlapStrategy()); 106 | $this->assertCount(2, $this->calendar); 107 | 108 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-15 15:30', '2012-01-15 15:59'))); 109 | $this->assertCount(3, $this->calendar); 110 | 111 | try { 112 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-15 15:00', '2012-01-15 15:40'))); 113 | $this->fail('A CalendarEventException should be thrown'); 114 | } catch (CalendarEventException $e) { 115 | } 116 | 117 | try { 118 | // exact same Event as reference 119 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-15 15:30', '2012-01-15 15:59'))); 120 | $this->fail('A CalendarEventException should be thrown'); 121 | } catch (CalendarEventException $e) { 122 | } 123 | 124 | $this->calendar->add(new Event(TimeIntervalFactory::create('2012-01-16 17:50', '2012-01-17 18:00'))); 125 | $this->assertCount(4, $this->calendar); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/Ddd/Calendar/Model/Calendar.php: -------------------------------------------------------------------------------- 1 | 19 | */ 20 | class Calendar implements CalendarInterface 21 | { 22 | /** 23 | * @var EventInterface[] 24 | */ 25 | private $events; 26 | 27 | /** 28 | * @var Event[] 29 | */ 30 | private $calendars; 31 | 32 | /** 33 | * @var StrategyInterface 34 | */ 35 | private $strategy; 36 | 37 | /** 38 | * @var string 39 | */ 40 | private $title; 41 | 42 | /** 43 | * @var TimePoint 44 | */ 45 | private $cursor; 46 | 47 | /** 48 | * @param string $title 49 | * @param array $events 50 | * @param StrategyInterface|null $strategy 51 | */ 52 | public function __construct($title, array $events = array(), StrategyInterface $strategy = null) 53 | { 54 | $this->strategy = (null === $strategy) ? new BaseStrategy() : $strategy; 55 | $this->title = $title; 56 | $this->events = array(); 57 | $this->calendars = array(); 58 | 59 | foreach ($events as $event) { 60 | $this->add($event); 61 | } 62 | $this->cursor = (0 === count($this->events)) ? TimePointFactory::now() : $this->events[0]->getInterval()->getBegin(); 63 | //$this->cursor = null; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function between(TimeInterval $interval, $title = '') 70 | { 71 | $selectedEvents = $this->getEvents($interval->getBegin(), $interval->getEnd()); 72 | $narrowerCalendar = new self($title, $selectedEvents, $this->strategy); 73 | 74 | return $narrowerCalendar; 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | public function getEventAfter(TimePoint $point) 81 | { 82 | foreach ($this->events as $event) { 83 | if ($event->getInterval()->getBegin()->isAfter($point)) { 84 | return $event; 85 | } 86 | } 87 | } 88 | 89 | /** 90 | * {@inheritdoc} 91 | */ 92 | public function add(EventInterface $newEvent) 93 | { 94 | $this->events = $this->strategy->add($newEvent, $this->events); 95 | $this->checkCursor(); 96 | } 97 | 98 | /** 99 | * {@inheritdoc} 100 | */ 101 | public function remove(EventInterface $event) 102 | { 103 | $this->events = $this->strategy->remove($event, $this->events); 104 | $this->checkCursor(); 105 | } 106 | 107 | /** 108 | * {@inheritdoc} 109 | */ 110 | public function update(EventInterface $originalEvent, EventInterface $updatedEvent) 111 | { 112 | $this->events = $this->strategy->update($originalEvent, $updatedEvent, $this->events); 113 | $this->checkCursor(); 114 | } 115 | 116 | /** 117 | * {@inheritdoc} 118 | */ 119 | public function setCursor(TimePoint $cursor) 120 | { 121 | $this->cursor = $cursor; 122 | } 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function getCursor() 128 | { 129 | return $this->cursor; 130 | } 131 | 132 | /** 133 | * @return string 134 | */ 135 | public function setTitle($title) 136 | { 137 | $this->title = $title; 138 | } 139 | 140 | public function getFirst() 141 | { 142 | return reset($this->events); 143 | } 144 | 145 | public function getLast() 146 | { 147 | return end($this->events); 148 | } 149 | 150 | public function group(Duration $duration) 151 | { 152 | $calendars = array(); 153 | $first = $current = $this->getFirst()->getInterval()->getBegin(); 154 | $end = $this->getLast()->getInterval()->getEnd(); 155 | while (!$current->isAfter($end)) { 156 | $newCurrent = $current->plus($duration); 157 | $this->calendars[] = $this->between($current->until($newCurrent)); 158 | $current = $newCurrent; 159 | } 160 | } 161 | 162 | public function getCalendars() 163 | { 164 | return $this->calendars; 165 | } 166 | 167 | /** 168 | * {@inheritdoc} 169 | */ 170 | public function getTitle() 171 | { 172 | return $this->title; 173 | } 174 | 175 | /** 176 | * @param StrategyInterface $strategy 177 | */ 178 | public function setStrategy($strategy) 179 | { 180 | $this->strategy = $strategy; 181 | } 182 | 183 | /** 184 | * @return StrategyInterface 185 | */ 186 | public function getStrategy() 187 | { 188 | return $this->strategy; 189 | } 190 | 191 | /** 192 | * {@inheritdoc} 193 | */ 194 | public function getIterator() 195 | { 196 | return new \ArrayIterator($this->getEvents($this->cursor)); 197 | } 198 | 199 | /** 200 | * {@inheritdoc} 201 | */ 202 | public function count() 203 | { 204 | return count($this->events); 205 | } 206 | 207 | /** 208 | * {@inheritdoc} 209 | */ 210 | public function countRemaining() 211 | { 212 | return count($this->getEvents($this->cursor)); 213 | } 214 | 215 | /** 216 | * @param TimePoint $begin 217 | * @param null|TimePoint $end 218 | * 219 | * @return array 220 | */ 221 | private function getEvents(TimePoint $begin, TimePoint $end = null) 222 | { 223 | $events = $this->events; 224 | 225 | $offset = 0; 226 | foreach ($events as $event) { 227 | if ($event->getInterval()->getEnd()->isAfter($begin) || $event->getInterval()->getEnd()->isEquals($begin)) { 228 | break; 229 | } else { 230 | $offset ++; 231 | } 232 | } 233 | $events = array_slice($events, $offset); 234 | 235 | if (null === $end) { 236 | return $events; 237 | } 238 | 239 | $length = count($events); 240 | foreach (array_reverse($events) as $event) { 241 | if ($end->isAfter($event->getInterval()->getBegin())) { 242 | break; 243 | } else { 244 | $length --; 245 | } 246 | } 247 | 248 | return array_slice($events, 0, $length); 249 | } 250 | 251 | public function offsetExists($offset) 252 | { 253 | return isset($this->events[$offset]); 254 | } 255 | 256 | public function offsetGet($offset) 257 | { 258 | return $this->offsetExists($offset) ? $this->events[$offset] : null; 259 | } 260 | 261 | public function offsetUnset($offset) 262 | { 263 | throw new BadMethodCallException('READ ONLY'); 264 | } 265 | 266 | public function offsetSet($offset, $value) 267 | { 268 | throw new BadMethodCallException('READ ONLY'); 269 | } 270 | 271 | private function checkCursor() 272 | { 273 | // @todo: implement this :) 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/Ddd/Time/Model/Duration.php: -------------------------------------------------------------------------------- 1 | value = $duration; 26 | $this->unit = $unit; 27 | 28 | if (TimeUnit::MONTH === $unit->getUnit() && (null === $year || null === $month)) { 29 | throw new \InvalidArgumentException(sprintf('Year and month should be provided to determine the duration.')); 30 | } 31 | 32 | if (TimeUnit::YEAR === $unit->getUnit() && null === $year) { 33 | throw new \InvalidArgumentException(sprintf('Year should be provided to determine the duration.')); 34 | } 35 | 36 | $this->year = $year; 37 | $this->month = $month; 38 | } 39 | 40 | public function asPHPDateInterval() 41 | { 42 | $timeSpec = ($this->unit->isTime()) ? 'PT' : 'P'; 43 | $timeSpec = sprintf('%s%s%s', $timeSpec, $this->value, $this->unit->getCode()); 44 | 45 | return new \DateInterval($timeSpec); 46 | } 47 | 48 | public function getValue() 49 | { 50 | return $this->value; 51 | } 52 | 53 | public function toSeconds() 54 | { 55 | if ($this->unit->getUnit() == TimeUnit::SECOND) { 56 | return $this; 57 | } 58 | 59 | if ($this->unit->getUnit() == TimeUnit::MINUTE) { 60 | return new Duration(self::NB_SECOND_PER_MINUTE * $this->value, TimeUnit::second()); 61 | } 62 | 63 | if ($this->unit->getUnit() == TimeUnit::HOUR) { 64 | return new Duration(self::NB_SECOND_PER_HOUR * $this->value, TimeUnit::second()); 65 | } 66 | 67 | if ($this->unit->getUnit() == TimeUnit::DAY) { 68 | return new Duration(self::NB_SECOND_PER_DAY * $this->value, TimeUnit::second()); 69 | } 70 | 71 | if ($this->unit->getUnit() == TimeUnit::WEEK) { 72 | return new Duration(self::NB_SECOND_PER_WEEK, TimeUnit::second()); 73 | } 74 | 75 | if (TimeUnit::MONTH === $this->unit->getUnit() || TimeUnit::YEAR === $this->unit->getUnit()) { 76 | return $this->toDays()->toSeconds(); 77 | } 78 | 79 | throw new \LogicException('Can\'t convert duration.'); 80 | } 81 | 82 | public function toMinutes() 83 | { 84 | if ($this->unit->getUnit() == TimeUnit::MINUTE) { 85 | return $this; 86 | } 87 | 88 | if ($this->unit->getUnit() == TimeUnit::SECOND) { 89 | return new Duration(floor($this->value / self::NB_SECOND_PER_MINUTE), TimeUnit::minute()); 90 | } 91 | 92 | if ($this->unit->getUnit() == TimeUnit::HOUR) { 93 | return new Duration(self::NB_MINUTE_PER_HOUR * $this->value, TimeUnit::minute()); 94 | } 95 | 96 | if ($this->unit->getUnit() == TimeUnit::DAY) { 97 | return new Duration(self::NB_MINUTE_PER_DAY * $this->value, TimeUnit::minute()); 98 | } 99 | 100 | if ($this->unit->getUnit() == TimeUnit::WEEK) { 101 | return new Duration(self::NB_MINUTE_PER_WEEK * $this->value, TimeUnit::minute()); 102 | } 103 | 104 | if (TimeUnit::MONTH === $this->unit->getUnit() || TimeUnit::YEAR === $this->unit->getUnit()) { 105 | return $this->toDays()->toMinutes(); 106 | } 107 | 108 | throw new \LogicException('Can\'t convert duration.'); 109 | } 110 | 111 | public function toHours() 112 | { 113 | if ($this->unit->getUnit() == TimeUnit::HOUR) { 114 | return $this; 115 | } 116 | 117 | if ($this->unit->getUnit() == TimeUnit::SECOND) { 118 | return new Duration(floor($this->value / (self::NB_SECOND_PER_HOUR)), TimeUnit::hour()); 119 | } 120 | 121 | if ($this->unit->getUnit() == TimeUnit::MINUTE) { 122 | return new Duration(floor($this->value / self::NB_MINUTE_PER_HOUR), TimeUnit::hour()); 123 | } 124 | 125 | if ($this->unit->getUnit() == TimeUnit::DAY) { 126 | return new Duration(self::NB_HOUR_PER_DAY * $this->value, TimeUnit::hour()); 127 | } 128 | 129 | if ($this->unit->getUnit() == TimeUnit::WEEK) { 130 | return new Duration(self::NB_HOUR_PER_WEEK * $this->value, TimeUnit::hour()); 131 | } 132 | 133 | if (TimeUnit::MONTH === $this->unit->getUnit() || TimeUnit::YEAR === $this->unit->getUnit()) { 134 | return $this->toDays()->toHours(); 135 | } 136 | 137 | throw new \LogicException('can\'t convert some years to hours.'); 138 | } 139 | 140 | public function toDays() 141 | { 142 | if ($this->unit->getUnit() == TimeUnit::DAY) { 143 | return $this; 144 | } 145 | 146 | if ($this->unit->getUnit() == TimeUnit::SECOND) { 147 | return new Duration(floor($this->value / self::NB_SECOND_PER_DAY), TimeUnit::day()); 148 | } 149 | 150 | if ($this->unit->getUnit() == TimeUnit::MINUTE) { 151 | return new Duration(floor($this->value / self::NB_MINUTE_PER_DAY), TimeUnit::day()); 152 | } 153 | 154 | if ($this->unit->getUnit() == TimeUnit::HOUR) { 155 | return new Duration(floor($this->value/ self::NB_HOUR_PER_DAY), TimeUnit::day()); 156 | } 157 | 158 | if ($this->unit->getUnit() == TimeUnit::WEEK) { 159 | return new Duration(self::NB_DAY_PER_WEEK * $this->value, TimeUnit::day()); 160 | } 161 | 162 | if ($this->unit->getUnit() == TimeUnit::MONTH) { 163 | $firstMonth = new \DateTime(); 164 | $firstMonth->setDate($this->year, $this->month, 1); 165 | $endMonth = new \DateTime(); 166 | $endMonth->setDate($this->year, $this->month, 1); 167 | $endMonth->add(new \DateInterval('P'.$this->value.'M')); 168 | $interval = $firstMonth->diff($endMonth); 169 | 170 | return new Duration($interval->days, TimeUnit::day()); 171 | } 172 | 173 | if ($this->unit->getUnit() == TimeUnit::YEAR) { 174 | $firstYear = new \DateTime(); 175 | $firstYear->setDate($this->year, 1, 1); 176 | $endYear = new \DateTime(); 177 | $endYear->setDate($this->year, 1, 1); 178 | $endYear->add(new \DateInterval('P'.$this->value.'Y')); 179 | $interval = $firstYear->diff($endYear); 180 | 181 | return new Duration($interval->days, TimeUnit::day()); 182 | } 183 | 184 | throw new \LogicException('can\'t convert some months or years to days.'); 185 | } 186 | 187 | public function toWeeks() 188 | { 189 | if ($this->unit->getUnit() == TimeUnit::WEEK) { 190 | return $this; 191 | } 192 | 193 | if ($this->unit->getUnit() == TimeUnit::SECOND) { 194 | return new Duration(floor($this->value / self::NB_SECOND_PER_WEEK), TimeUnit::week()); 195 | } 196 | 197 | if ($this->unit->getUnit() == TimeUnit::MINUTE) { 198 | return new Duration(floor($this->value / self::NB_MINUTE_PER_WEEK), TimeUnit::week()); 199 | } 200 | 201 | if ($this->unit->getUnit() == TimeUnit::HOUR) { 202 | return new Duration(floor($this->value / self::NB_HOUR_PER_WEEK), TimeUnit::week()); 203 | } 204 | 205 | if ($this->unit->getUnit() == TimeUnit::DAY) { 206 | return new Duration(floor($this->value / self::NB_DAY_PER_WEEK), TimeUnit::week()); 207 | } 208 | 209 | throw new \LogicException('can\'t convert some months or years to weeks.'); 210 | } 211 | } 212 | --------------------------------------------------------------------------------