Статьи

Предлагая Углерод с Композитором — Дата и Время Правильный путь

Carbon — небольшая библиотека для манипулирования датой и временем в PHP. Он опирается на базовый класс DateTime и расширяет его, добавляя полезные методы для более удобного использования.

В этой статье мы рассмотрим некоторые основные примеры использования, а затем используем его в реальном проекте.

Дата и время изображения

Вступление

Carbon — это просто класс, который предназначен для использования вместо DateTime. Благодаря расширению DateTime все методы DateTime доступны пользователям Carbon. Кроме того, он реализует __toString , позволяющий пользователям размещать его вместо строковых представлений даты и времени.

Его можно легко установить с помощью Composer:

 composer require nesbot/carbon 

Давайте рассмотрим некоторые примеры использования, представленные в их отличной документации .

Пример использования

Самый простой способ начать работу с Carbon — просто передать читаемую человеком строку даты в ее конструктор вместе с необязательным часовым поясом — если часовой пояс пропущен, будет использоваться тот, который установлен текущей установкой PHP.

 $carbon = new Carbon('first day of next week'); 

Он также может быть создан из строк, временных отметок, даже других экземпляров DateTime или даже Carbon. Экземпляр можно скопировать с помощью метода copy() для эффективного клонирования.

Оттуда у нас есть доступ к шведскому столу вспомогательных шашек и добытчиков:

 $carbon->isWeekend(); $carbon->isFuture(); $carbon->isLeapYear(); $carbon->year; $carbon->month; $carbon->daysInMonth; $carbon->weekOfYear; 

Пакет также предоставляет статические методы для быстрого создания новых экземпляров:

 echo Carbon::now()->addYear()->diffForHumans(); // in 1 year 

Даже дни рождения можно проверить, как мы видим из этого примера из документов:

 $born = Carbon::createFromDate(1987, 4, 23); $noCake = Carbon::createFromDate(2014, 9, 26); $yesCake = Carbon::createFromDate(2014, 4, 23); $overTheHill = Carbon::now()->subYears(50); var_dump($born->isBirthday($noCake)); // bool(false) var_dump($born->isBirthday($yesCake)); // bool(true) var_dump($overTheHill->isBirthday()); // bool(true) -> default compare it to today! 

локализация

Также поддерживается локализация, так что вывод можно производить на любом желаемом языке, установленном на компьютере, на котором работает приложение PHP. Обратите внимание, что вам нужно установить необходимые локали для того, чтобы это работало — обратитесь к документации вашей операционной системы за подробной информацией о том, как это сделать.

Для локализации строк даты и времени можно использовать стандартную функцию PHP setlocale :

 setlocale(LC_TIME, 'German'); echo $dt->formatLocalized('%A %d %B %Y'); // Mittwoch 21 Mai 1975 

Чтобы локализовать метод diffForHumans который выводит diffForHumans человеку разницу во времени, класс предлагает свой собственный метод setLocale :

 Carbon::setLocale('de'); echo Carbon::now()->addYear()->diffForHumans(); // in 1 Jahr 

интервал

Также предоставляется класс CarbonInterval, который является расширением DateInterval . Информативно, он содержит значения интервалов, как и базовый класс, но добавляет вспомогательные методы сверху. Согласно примерам:

 echo CarbonInterval : : year ( ) ;  // 1 year echo CarbonInterval : : months ( 3 ) ;  // 3 months echo CarbonInterval : : days ( 3 ) - > seconds ( 32 ) ;  // 3 days 32 seconds echo CarbonInterval : : weeks ( 3 ) ;  // 3 weeks echo CarbonInterval : : days ( 23 ) ;  // 3 weeks 2 days echo CarbonInterval : : create ( 2 , 0 , 5 , 1 , 1 , 2 , 7 ) ;  // 2 years 5 weeks 1 day 1 hour 2 minutes 7 seconds 

Обратите внимание, что Carbon в целом исключительно хорошо документирован — для полного ознакомления с методами и примерами использования, пожалуйста, смотрите их документы .

Реализация

В этом разделе мы обновим PHP-клиент Diffbot для дополнительной поддержки Carbon. План следующий: если у пользователя установлена ​​библиотека, сущность Article и сущность Post будут возвращать экземпляры Carbon вместо строк даты из своих getDate и getEstimatedDate . В противном случае они будут возвращать строки как обычно.

Если вы хотите следовать, клонируйте клиента в этой версии .

Композитор предлагает

Первым шагом является добавление библиотеки в список предложений в composer.json . Список suggests принимает тот же формат, что и блоки require , но вместо ограничений версии мы помещаем полные строковые сообщения о том, почему предлагается этот пакет.

 "suggest": { "nesbot/carbon": "Turns the date and estimatedDate return values of Article and Post entity into Carbon entities." }, 

Мы можем убедиться в правильности синтаксиса, запустив composer validate :

 vagrant@homestead:~/Code/diffbot-php-client$ composer validate ./composer.json is valid 

Когда пользователь устанавливает PHP-клиент Diffbot, он увидит рекомендацию установить Carbon.

тесты

Затем пришло время обновить тесты, чтобы приспособиться к этому.

В tests/Entities/ArticleTest.php мы testDate функции dateProvider и testDate следующим образом:

 public function dateProvider ( ) { return [ [ 'Articles/diffbot-sitepoint-basic.json' , "Sun, 27 Jul 2014 00:00:00 GMT" , 2014 ] , [ 'Articles/diffbot-sitepoint-extended.json' , "Sun, 27 Jul 2014 00:00:00 GMT" , 2014 ] , [ 'Articles/apple-watch-verge-basic.json' , "Wed, 08 Apr 2015 00:00:00 GMT" , 2015 ] , [ 'Articles/apple-watch-verge-extended.json' , "Wed, 08 Apr 2015 00:00:00 GMT" , 2015 ] ] ; } /** * @param $file * @param $articles * @dataProvider dateProvider */ public function testDate ( $file , $articles , $year ) { $articles = ( is_array ( $articles ) ) ? $articles : [ $articles ] ; /** @var Article $entity */ foreach ( $this - > ei ( $file ) as $i = > $entity ) { $this - > assertEquals ( $articles [ $i ] , $entity - > getDate ( ) ) ; if ( class_exists ( '\Carbon\Carbon' ) ) { $this - > assertEquals ( $year , $entity - > getDate ( ) - > year ) ; } } } 

Что здесь случилось?

Сначала мы добавили значения года в провайдера в качестве третьего аргумента для передачи в testDate . Затем, во время итерации и утверждения, мы сначала проверяем, загружен ли класс / существует, и если это так, мы проверяем один из его получателей ( ->year ).

Мы должны проверить, существует ли класс перед тестированием, потому что Carbon является необязательным в Diffbot SDK — это всего лишь предложение, поэтому мы не должны ошибаться, если его там нет.

Мы повторяем процесс ArticleTest и ArticleTest в нижней части класса ArticleTest :

 public function estimatedDateProvider ( ) { return [ [ 'Articles/15-11-07/diffbot-sitepoint-basic.json' , 'Sun, 27 Jul 2014 00:00:00 GMT' , 2014 ] , ] ; } /** * @dataProvider estimatedDateProvider * @param $file * @param $value1 */ public function testEstimatedDate ( $file , $value1 , $value2 ) { $value1 = ( is_array ( $value1 ) ) ? $value1 : [ $value1 ] ; /** @var Article $entity */ foreach ( $this - > ei ( $file ) as $i = > $entity ) { $this - > assertEquals ( $value1 [ $i ] , $entity - > getEstimatedDate ( ) ) ; if ( class_exists ( '\Carbon\Carbon' ) ) { $this - > assertEquals ( $value2 , $entity - > getDate ( ) - > year ) ; } } } 

Далее давайте обновим класс PostTest . В этом методе есть только метод getDate , но он требует немного большего набора текста, потому что Обсуждение почти всегда возвращает несколько сообщений.

 { return [ [ 'Discussions/15-05-01/sp_discourse_php7_recap.json' , [ "Wed, 29 Apr 2015 16:00:00 GMT" , "Thu, 30 Apr 2015 01:13:00 GMT" , "Thu, 30 Apr 2015 05:55:00 GMT" , "Thu, 30 Apr 2015 06:57:00 GMT" , "Thu, 30 Apr 2015 07:51:00 GMT" , "Thu, 30 Apr 2015 09:29:00 GMT" , "Thu, 30 Apr 2015 10:26:00 GMT" , "Thu, 30 Apr 2015 10:40:00 GMT" , "Thu, 30 Apr 2015 11:06:00 GMT" , "Thu, 30 Apr 2015 11:29:00 GMT" , "Thu, 30 Apr 2015 14:33:00 GMT" , "Thu, 30 Apr 2015 15:48:00 GMT" , "Thu, 30 Apr 2015 16:17:00 GMT" , "Thu, 30 Apr 2015 16:51:00 GMT" , "Thu, 30 Apr 2015 17:02:00 GMT" , "Fri, 01 May 2015 08:00:00 GMT" , ] , [ 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , 2015 , ] ] ] ; } /** * @param $file * @param $posts * @dataProvider dateProvider */ public function testDate ( $file , $posts , $years ) { /** @var Discussion $entity */ foreach ( $this - > ei ( $file ) as $entity ) { /** @var Post $post */ foreach ( $entity - > getPosts ( ) as $i = > $post ) { $this - > assertEquals ( $posts [ $i ] , $post - > getDate ( ) ) ; if ( class_exists ( '\Carbon\Carbon' ) ) { $this - > assertEquals ( $years [ $i ] , $post - > getDate ( ) - > year ) ; } } } } 

Если мы сейчас попытаемся запустить эти тесты, они пройдут успешно. Если мы установим Carbon в проект с:

 composer require nesbot/carbon --dev 

… испытания не пройдут.

Реализация

Пришло время изменить реальные объекты сейчас.

Diffbot возвращает даты в следующем формате: Sun, 27 Jul 2014 00:00:00 GMT .

Чтобы поддерживать обратную совместимость, нам нужно настроить Carbon на выдачу одинакового вывода при использовании в виде строки (через __toString ), чтобы каждый, кто использовал значения даты в качестве вывода напрямую, все еще мог это сделать. Это делается с помощью статического Carbon::setToStringFormat($format); метод.

Добавление следующего к конструктору в src/Entity/Article.php позволит сделать это:

 if ( class_exists ( '\Carbon\Carbon' ) ) { $format = 'D, d M o H:i:s e' ; \ Carbon \ Carbon : : setToStringFormat ( $format ) ; } 

То же самое должно быть добавлено в файл src/Entity/Post.php , хотя он все еще не переопределяет конструктор базового класса и должен сделать это в первую очередь. Финальная версия метода конструктора Post :

 public function __construct ( array $data ) { if ( class_exists ( '\Carbon\Carbon' ) ) { $format = 'D, d M o H:i:s e' ; \ Carbon \ Carbon : : setToStringFormat ( $format ) ; } parent : : __construct ( $data ) ; } 

Теперь, когда у нас активирован Carbon и по умолчанию выбран нужный нам формат, пришло время обновить наши геттеры.

И в Article и в Post метод getDate теперь должен выглядеть следующим образом:

 public function getDate ( ) { return ( class_exists ( '\Carbon\Carbon' ) ) ? new \ Carbon \ Carbon ( $this - > data [ 'date' ] , 'GMT' ) : $this - > data [ 'date' ] ; } 

Если Carbon существует, создайте новый экземпляр из даты публикации в часовом поясе GMT ​​(часовой пояс всегда возвращается), в противном случае верните строку даты, как и раньше.

Наконец, нам нужно изменить getEstimatedDate в Article :

 public function getEstimatedDate ( ) { $date = $this - > getOrDefault ( 'estimatedDate' , $this - > getDate ( ) ) ; return ( class_exists ( '\Carbon\Carbon' ) ) ? new \ Carbon \ Carbon ( $date , 'GMT' ) : $date ; } 

То же самое, только это первое значение по умолчанию getDate если estimatedDate getDate не может быть определена.

Запуск тестов теперь должен показать все прохождение:

 vagrant@homestead:~/Code/diffbot-php-client$ phpunit PHPUnit 5.0.8 by Sebastian Bergmann and contributors. Runtime: PHP 5.6.10-1+deb.sury.org~trusty+1 with Xdebug 2.3.2 Configuration: /home/vagrant/Code/diffbot-php-client/phpunit.xml.dist ............................................................... 63 / 352 ( 17%) ............................................................... 126 / 352 ( 35%) ............S.................................................. 189 / 352 ( 53%) ............................................................... 252 / 352 ( 71%) ............................................................... 315 / 352 ( 89%) ..................................... 352 / 352 (100%) Time: 49.39 seconds, Memory: 21.00Mb 

Успех! Теперь мы можем зафиксировать, отправить и опубликовать новый выпуск!

Вывод

Мы рассмотрели Carbon, расширение DateTime, которое добавляет полезные методы в базовый класс и делает его гораздо более приятным в использовании. Мы увидели, как это легко реализовать в проекте и как он может заменить чистые строковые выходные данные и временные метки с помощью различных внутренних форматов строк.

Вы используете Carbon в своих проектах? Что вам нравится или не нравится в этом? Оставьте свои мысли и комментарии ниже, и если вам понравился этот пост, не забудьте нажать на эту кнопку!