Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: #196 Introduce a custom DatePeriodFilter that safely copies DatePeriod objects without modifying their readonly properties. #197

Merged
merged 2 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/DeepCopy/DeepCopy.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use ArrayObject;
use DateInterval;
use DatePeriod;
use DateTimeInterface;
use DateTimeZone;
use DeepCopy\Exception\CloneException;
Expand All @@ -12,6 +13,7 @@
use DeepCopy\Matcher\Matcher;
use DeepCopy\Reflection\ReflectionHelper;
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
use DeepCopy\TypeFilter\Date\DatePeriodFilter;
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
use DeepCopy\TypeFilter\TypeFilter;
Expand Down Expand Up @@ -64,6 +66,7 @@ public function __construct($useCloneMethod = false)

$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
$this->addTypeFilter(new DatePeriodFilter(), new TypeMatcher(DatePeriod::class));
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
}

Expand Down
42 changes: 42 additions & 0 deletions src/DeepCopy/TypeFilter/Date/DatePeriodFilter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

namespace DeepCopy\TypeFilter\Date;

use DatePeriod;
use DeepCopy\TypeFilter\TypeFilter;

/**
* @final
*/
class DatePeriodFilter implements TypeFilter
{
/**
* {@inheritdoc}
*
* @param DatePeriod $element
*
* @see http://news.php.net/php.bugs/205076
*/
public function apply($element)
{
$options = 0;
if (PHP_VERSION_ID >= 80200 && $element->include_end_date) {
$options |= DatePeriod::INCLUDE_END_DATE;
}
if (!$element->include_start_date) {
$options |= DatePeriod::EXCLUDE_START_DATE;
}

if ($element->getEndDate()) {
return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $element->getEndDate(), $options);
}

if (PHP_VERSION_ID >= 70217) {
$recurrences = $element->getRecurrences();
} else {
$recurrences = $element->recurrences - $element->include_start_date;
}

return new DatePeriod($element->getStartDate(), $element->getDateInterval(), $recurrences, $options);
}
}
3 changes: 3 additions & 0 deletions tests/DeepCopyTest/DeepCopyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use ArrayObject;
use DateInterval;
use DatePeriod;
use DateTime;
use DateTimeImmutable;
use DateTimeZone;
Expand Down Expand Up @@ -158,13 +159,15 @@ public function test_it_can_copy_an_object_with_a_date_object_property()
$object->d2 = new DateTimeImmutable();
$object->dtz = new DateTimeZone('UTC');
$object->di = new DateInterval('P2D');
$object->dp = new DatePeriod(new DateTime(), new DateInterval('P2D'), 3);

$copy = deep_copy($object);

$this->assertEqualButNotSame($object->d1, $copy->d1);
$this->assertEqualButNotSame($object->d2, $copy->d2);
$this->assertEqualButNotSame($object->dtz, $copy->dtz);
$this->assertEqualButNotSame($object->di, $copy->di);
$this->assertEqualButNotSame($object->dp, $copy->dp);
}

/**
Expand Down
67 changes: 67 additions & 0 deletions tests/DeepCopyTest/TypeFilter/Date/DatePeriodFilterTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php declare(strict_types=1);

namespace DeepCopyTest\TypeFilter\Date;

use DateInterval;
use DatePeriod;
use DateTime;
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
use DeepCopy\TypeFilter\Date\DatePeriodFilter;
use PHPUnit\Framework\TestCase;

/**
* @covers \DeepCopy\TypeFilter\Date\DatePeriodFilter
*/
class DatePeriodFilterTest extends TestCase
{
public function test_it_deep_copies_a_DatePeriod()
{
$object = new DatePeriod(new DateTime(), new DateInterval('P2D'), 3);

$filter = new DatePeriodFilter();

$copy = $filter->apply($object);

$this->assertEquals($object, $copy);
$this->assertNotSame($object, $copy);
}

public function test_it_deep_copies_a_DatePeriod_with_exclude_start_date()
{
$object = new DatePeriod(new DateTime(), new DateInterval('P2D'), 3, DatePeriod::EXCLUDE_START_DATE);

$filter = new DatePeriodFilter();

$copy = $filter->apply($object);

$this->assertEquals($object, $copy);
$this->assertNotSame($object, $copy);
}

/**
* @requires PHP 8.2
*/
public function test_it_deep_copies_a_DatePeriod_with_include_end_date()
{
$object = new DatePeriod(new DateTime(), new DateInterval('P2D'), 3, DatePeriod::INCLUDE_END_DATE);

$filter = new DatePeriodFilter();

$copy = $filter->apply($object);

$this->assertEquals($object, $copy);
$this->assertNotSame($object, $copy);
}

public function test_it_deep_copies_a_DatePeriod_with_end_date()
{
$object = new DatePeriod(new DateTime(), new DateInterval('P2D'), new DateTime('+2 days'));

$filter = new DatePeriodFilter();

$copy = $filter->apply($object);

$this->assertEquals($object, $copy);
$this->assertNotSame($object, $copy);
}
}