Commit 422d81d8 authored by rlgy's avatar rlgy

账单

parent cae4b465
......@@ -24,6 +24,3 @@ composer.lock
# linux file system
/.directory
# vendor files
vendor
<?php
namespace Codeception\Lib\Connector\Yii2;
use yii\base\Event;
use yii\db\Connection;
/**
* Class ConnectionWatcher
* This class will watch for new database connection and store a reference to the connection object.
* @package Codeception\Lib\Connector\Yii2
*/
class ConnectionWatcher
{
private $handler;
/** @var Connection[] */
private $connections = [];
public function __construct()
{
$this->handler = function (Event $event) {
if ($event->sender instanceof Connection) {
$this->connectionOpened($event->sender);
}
};
}
protected function connectionOpened(Connection $connection)
{
$this->debug('Connection opened!');
if ($connection instanceof Connection) {
$this->connections[] = $connection;
}
}
public function start()
{
Event::on(Connection::class, Connection::EVENT_AFTER_OPEN, $this->handler);
$this->debug('watching new connections');
}
public function stop()
{
Event::off(Connection::class, Connection::EVENT_AFTER_OPEN, $this->handler);
$this->debug('no longer watching new connections');
}
public function closeAll()
{
$count = count($this->connections);
$this->debug("closing all ($count) connections");
foreach ($this->connections as $connection) {
$connection->close();
}
}
protected function debug($message)
{
$title = (new \ReflectionClass($this))->getShortName();
if (is_array($message) or is_object($message)) {
$message = stripslashes(json_encode($message));
}
codecept_debug("[$title] $message");
}
}
<?php
namespace Codeception\Lib\Connector\Yii2;
use yii\base\Event;
use yii\db\Connection;
use yii\db\Transaction;
/**
* Class TransactionForcer
* This class adds support for forcing transactions as well as reusing PDO objects.
* @package Codeception\Lib\Connector\Yii2
*/
class TransactionForcer extends ConnectionWatcher
{
private $ignoreCollidingDSN;
private $pdoCache = [];
private $dsnCache;
private $transactions = [];
public function __construct(
$ignoreCollidingDSN
) {
parent::__construct();
$this->ignoreCollidingDSN = $ignoreCollidingDSN;
}
protected function connectionOpened(Connection $connection)
{
parent::connectionOpened($connection);
/**
* We should check if the known PDO objects are the same, in which case we should reuse the PDO
* object so only 1 transaction is started and multiple connections to the same database see the
* same data (due to writes inside a transaction not being visible from the outside).
*
*/
$key = md5(json_encode([
'dsn' => $connection->dsn,
'user' => $connection->username,
'pass' => $connection->password,
'attributes' => $connection->attributes,
'emulatePrepare' => $connection->emulatePrepare,
'charset' => $connection->charset
]));
/*
* If keys match we assume connections are "similar enough".
*/
if (isset($this->pdoCache[$key])) {
$connection->pdo = $this->pdoCache[$key];
} else {
$this->pdoCache[$key] = $connection->pdo;
}
if (isset($this->dsnCache[$connection->dsn])
&& $this->dsnCache[$connection->dsn] !== $key
&& !$this->ignoreCollidingDSN
) {
$this->debug(<<<TEXT
You use multiple connections to the same DSN ({$connection->dsn}) with different configuration.
These connections will not see the same database state since we cannot share a transaction between different PDO
instances.
You can remove this message by adding 'ignoreCollidingDSN = true' in the module configuration.
TEXT
);
Debug::pause();
}
if (isset($this->transactions[$key])) {
$this->debug('Reusing PDO, so no need for a new transaction');
return;
}
$this->debug('Transaction started for: ' . $connection->dsn);
$this->transactions[$key] = $connection->beginTransaction();
}
public function rollbackAll()
{
/** @var Transaction $transaction */
foreach ($this->transactions as $transaction) {
if ($transaction->db->isActive) {
$transaction->rollBack();
$this->debug('Transaction cancelled; all changes reverted.');
}
}
$this->transactions = [];
$this->pdoCache = [];
$this->dsnCache = [];
}
}
<?php
class ConfigExtendsCest
{
/**
* @param CliGuy $I
*/
public function runIncludedSuites(\CliGuy $I)
{
$I->amInPath('tests/data/config_extends');
$I->executeCommand('run');
$I->seeInShellOutput('UnitCest');
$I->seeInShellOutput('OK (1 test, 1 assertion)');
$I->dontSeeInShellOutput('Exception');
}
}
paths:
tests: tests
log: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 2048M
extensions:
enabled:
- Codeception\Extension\RunFailed
actor: Tester
extends: codeception.common.yml
<?php
/**
* Inherited Methods
* @method void wantToTest($text)
* @method void wantTo($text)
* @method void execute($callable)
* @method void expectTo($prediction)
* @method void expect($prediction)
* @method void amGoingTo($argumentation)
* @method void am($role)
* @method void lookForwardTo($achieveValue)
* @method void comment($description)
* @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
*
* @SuppressWarnings(PHPMD)
*/
class UnitTester extends \Codeception\Actor
{
use _generated\UnitTesterActions;
/**
* Define custom actions here
*/
}
# Codeception Test Suite Configuration
#
# Suite for unit (internal) tests.
class_name: UnitTester
extends: unit.suite.common.yml
<?php
class UnitCest
{
public function successful(UnitTester $I)
{
$I->assertTrue(true);
}
}
<?php
namespace Faker\Calculator;
use InvalidArgumentException;
class TCNo
{
/**
* Generates Turkish Identity Number Checksum
* Gets first 9 digit as prefix and calcuates checksums
*
* https://en.wikipedia.org/wiki/Turkish_Identification_Number
*
* @param string $identityPrefix
* @return string Checksum (two digit)
*/
public static function checksum($identityPrefix)
{
if (strlen((string)$identityPrefix) !== 9) {
throw new InvalidArgumentException('Argument should be an integer and should be 9 digits.');
}
$oddSum = 0;
$evenSum = 0;
$identityArray = array_map('intval', str_split($identityPrefix)); // Creates array from int
foreach ($identityArray as $index => $digit) {
if ($index % 2 == 0) {
$evenSum += $digit;
} else {
$oddSum += $digit;
}
}
$tenthDigit = (7 * $evenSum - $oddSum) % 10;
$eleventhDigit = ($evenSum + $oddSum + $tenthDigit) % 10;
return $tenthDigit . $eleventhDigit;
}
/**
* Checks whether an TCNo has a valid checksum
*
* @param string $tcNo
* @return boolean
*/
public static function isValid($tcNo)
{
return self::checksum(substr($tcNo, 0, -2)) === substr($tcNo, -2, 2);
}
}
This diff is collapsed.
This diff is collapsed.
<?php
namespace Faker\Provider\ms_MY;
class Miscellaneous extends \Faker\Provider\Miscellaneous
{
/**
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia
*/
protected static $jpjNumberPlateFormats = array(
'{{peninsularPrefix}}{{validAlphabet}}{{validAlphabet}} {{numberSequence}}',
'{{peninsularPrefix}}{{validAlphabet}}{{validAlphabet}} {{numberSequence}}',
'{{peninsularPrefix}}{{validAlphabet}}{{validAlphabet}} {{numberSequence}}',
'{{peninsularPrefix}}{{validAlphabet}}{{validAlphabet}} {{numberSequence}}',
'W{{validAlphabet}}{{validAlphabet}} {{numberSequence}} {{validAlphabet}}',
'KV {{numberSequence}} {{validAlphabet}}',
'{{sarawakPrefix}} {{numberSequence}} {{validAlphabet}}',
'{{sabahPrefix}} {{numberSequence}} {{validAlphabet}}',
'{{specialPrefix}} {{numberSequence}}',
);
/**
* Some alphabet has higher frequency that coincides with the current number
* of registrations. E.g. W = Wilayah Persekutuan
*
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#Current_format
*/
protected static $peninsularPrefix = array(
'A','A','B','C','D','F','J','J','K','M','N','P','P','R','T','V',
'W','W','W','W','W','W',
);
/**
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#Current_format_2
*/
protected static $sarawakPrefix = array(
'QA','QK','QB','QC','QL','QM','QP','QR','QS','QT'
);
/**
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#Current_format_3
*/
protected static $sabahPrefix = array(
'SA','SAA','SAB','SAC','SB','SD','SG',
'SK','SL','SS','SSA','ST','STA','SU'
);
/**
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#Commemorative_plates
*/
protected static $specialPrefix = array(
'1M4U',
'A1M',
'BAMbee',
'Chancellor',
'G','G1M','GP','GT',
'Jaguh',
'K1M','KRISS',
'LOTUS',
'NAAM','NAZA','NBOS',
'PATRIOT','Perdana','PERFECT','Perodua','Persona','Proton','Putra','PUTRAJAYA',
'RIMAU',
'SAM','SAS','Satria','SMS','SUKOM',
'T1M','Tiara','TTB',
'U','US',
'VIP',
'WAJA',
'XIIINAM','XOIC','XXVIASEAN','XXXIDB',
'Y'
);
/**
* Chances of having an empty alphabet will be 1/24
*
* @link https://en.wikipedia.org/wiki/Vehicle_registration_plates_of_Malaysia#Current_format
*/
protected static $validAlphabets = array(
'A','B','C','D','E','F',
'G','H','J','K','L','M',
'N','P','Q','R','S','T',
'U','V','W','X','Y',''
);
/**
* Return a valid Malaysia JPJ(Road Transport Department) vehicle licence plate number
*
* @example 'WKN 2368'
*
* @return @string
*/
public function jpjNumberPlate()
{
$formats = static::toUpper(static::lexify(static::bothify(static::randomElement(static::$jpjNumberPlateFormats))));
return $this->generator->parse($formats);
}
/**
* Return Peninsular prefix alphabet
*
* @example 'W'
*
* @return @string
*/
public static function peninsularPrefix()
{
return static::randomElement(static::$peninsularPrefix);
}
/**
* Return Sarawak state prefix alphabet
*
* @example 'QA'
*
* @return @string
*/
public static function sarawakPrefix()
{
return static::randomElement(static::$sarawakPrefix);
}
/**
* Return Sabah state prefix alphabet
*
* @example 'SA'
*
* @return @string
*/
public static function sabahPrefix()
{
return static::randomElement(static::$sabahPrefix);
}
/**
* Return specialty licence plate prefix
*
* @example 'G1M'
*
* @return @string
*/
public static function specialPrefix()
{
return static::randomElement(static::$specialPrefix);
}
/**
* Return a valid license plate alphabet
*
* @example 'A'
*
* @return @string
*/
public static function validAlphabet()
{
return static::randomElement(static::$validAlphabets);
}
/**
* Return a valid number sequence between 1 and 9999
*
* @example '1234'
*
* @return @integer
*/
public static function numberSequence()
{
return mt_rand(1, 9999);
}
}
<?php
namespace Faker\Provider\ms_MY;
class Payment extends \Faker\Provider\Payment
{
protected static $bankFormats = array(
'{{localBank}}',
'{{foreignBank}}',
'{{governmentBank}}'
);
/**
* @link http://www.muamalat.com.my/consumer-banking/internet-banking/popup-ibg.html
*/
protected static $bankAccountNumberFormats = array(
'##########',
'###########',
'############',
'#############',
'##############',
'###############',
'################',
);
/**
* @link https://en.wikipedia.org/wiki/List_of_banks_in_Malaysia
*/
protected static $localBanks = array(
'Affin Bank',
'Alliance Bank',
'AmBank',
'CIMB Bank',
'Hong Leong Bank ',
'Maybank',
'Public Bank',
'RHB Bank'
);
/**
* @link https://en.wikipedia.org/wiki/List_of_banks_in_Malaysia#List_of_foreign_banks_(commercial)
*/
protected static $foreignBanks = array(
'Bangkok Bank Berhad',
'Bank of America Malaysia Berhad',
'Bank of China (Malaysia) Berhad',
'Bank of Tokyo-Mitsubishi UFJ (Malaysia) Berhad',
'BNP Paribas Malaysia Berhad',
'China Construction Bank',
'Citibank Berhad',
'Deutsche Bank (Malaysia) Berhad',
'HSBC Bank Malaysia Berhad',
'India International Bank (Malaysia) Berhad',
'Industrial and Commercial Bank of China (Malaysia) Berhad',
'J.P. Morgan Chase Bank Berhad',
'Mizuho Bank (Malaysia) Berhad',
'National Bank of Abu Dhabi Malaysia Berhad',
'OCBC Bank (Malaysia) Berhad',
'Standard Chartered Bank Malaysia Berhad',
'Sumitomo Mitsui Banking Corporation Malaysia Berhad',
'The Bank of Nova Scotia Berhad',
'United Overseas Bank (Malaysia) Bhd.'
);
/**
* @link https://en.wikipedia.org/wiki/List_of_banks_in_Malaysia#Development_Financial_Institutions_(Government-owned_banks)_(full_list)
*/
protected static $governmentBanks = array(
'Agro Bank Malaysia',
'Bank Pembangunan Malaysia Berhad (BPMB) (The development bank of Malaysia)',
'Bank Rakyat',
'Bank Simpanan Nasional',
'Credit Guarantee Corporation Malaysia Berhad (CGC)',
'Export-Import Bank of Malaysia Berhad (Exim Bank)',
'Malaysia Debt Ventures Berhad',
'Malaysian Industrial Development Finance Berhad (MIDF)',
'SME Bank Berhad',
'Sabah Development Bank Berhad (SDB)',
'Sabah Credit Corporation (SCC)',
'Tabung Haji',
);
/**
* @link https://en.wikipedia.org/wiki/List_of_banks_in_Malaysia#Investment-Link_Funds_(Insurance_Companies_-_Takaful_included)
*/
protected static $insuranceCompanies = array(
'AIA Malaysia',
'AIG Malaysia',
'Allianz Malaysia',
'AXA AFFIN Life Insurance',
'Berjaya General Insurance',
'Etiqa Insurance',
'Great Eastern Insurance',
'Hong Leong Assurance',
'Kurnia Insurans Malaysia',
'Manulife Malaysia Insurance',
'MSIG Malaysia',
'Prudential Malaysia',
'Tokio Marine Life Malaysia Insurance',
'UNI.ASIA General Insurance',
'Zurich Insurance Malaysia',
);
/**
* @link http://www.bankswiftcode.org/malaysia/
*/
protected static $swiftCodes = array(
'ABNAMY2AXXX','ABNAMYKLPNG','ABNAMYKLXXX','AFBQMYKLXXX','AIBBMYKLXXX',
'AISLMYKLXXX','AMMBMYKLXXX','ARBKMYKLXXX',
'BIMBMYKLXXX','BISLMYKAXXX','BKCHMYKLXXX','BKKBMYKLXXX','BMMBMYKLXXX',
'BNMAMYKLXXX','BNPAMYKAXXX','BOFAMY2XLBN','BOFAMY2XXXX','BOTKMYKAXXX',
'BOTKMYKXXXX',
'CHASMYKXKEY','CHASMYKXXXX','CIBBMYKAXXX','CIBBMYKLXXX','CITIMYKLJOD',
'CITIMYKLLAB','CITIMYKLPEN','CITIMYKLXXX','COIMMYKLXXX','CTBBMYKLXXX',
'DABEMYKLXXX','DBSSMY2AXXX','DEUTMYKLBLB','DEUTMYKLGMO','DEUTMYKLISB',
'DEUTMYKLXXX',
'EIBBMYKLXXX','EOBBMYKLXXX','EXMBMYKLXXX',
'FEEBMYKAXXX',
'HBMBMYKLXXX','HDSBMY2PSEL','HDSBMY2PXXX','HLBBMYKLIBU','HLBBMYKLJBU',
'HLBBMYKLKCH','HLBBMYKLPNG','HLBBMYKLXXX','HLIBMYKLXXX','HMABMYKLXXX',
'HSBCMYKAXXX','HSTMMYKLGWS','HSTMMYKLXXX',
'KAFBMYKLXXX','KFHOMYKLXXX',
'MBBEMYKAXXX','MBBEMYKLBAN','MBBEMYKLBBG','MBBEMYKLBWC','MBBEMYKLCSD',
'MBBEMYKLIPH','MBBEMYKLJOB','MBBEMYKLKEP','MBBEMYKLKIN','MBBEMYKLKLC',
'MBBEMYKLMAL','MBBEMYKLPEN','MBBEMYKLPGC','MBBEMYKLPJC','MBBEMYKLPJY',
'MBBEMYKLPKG','MBBEMYKLPSG','MBBEMYKLPUD','MBBEMYKLSAC','MBBEMYKLSBN',
'MBBEMYKLSHA','MBBEMYKLSUB','MBBEMYKLWSD','MBBEMYKLXXX','MBBEMYKLYSL',
'MFBBMYKLXXX','MHCBMYKAXXX',
'NOSCMY2LXXX','NOSCMYKLXXX',
'OABBMYKLXXX','OCBCMYKLXXX','OSKIMYKLXXX',
'PBBEMYKLXXX','PBLLMYKAXXX','PCGLMYKLXXX','PERMMYKLXXX','PHBMMYKLXXX',
'PTRDMYKLXXX','PTROMYKLFSD','PTROMYKLXXX',
'RHBAMYKLXXX','RHBBMYKAXXX','RHBBMYKLXXX','RJHIMYKLXXX',
'SCBLMYKXLAB','SCBLMYKXXXX','SMBCMYKAXXX',
'UIIBMYKLXXX','UOVBMYKLCND','UOVBMYKLXXX',
);
/**
* @link https://en.wikipedia.org/wiki/Malaysian_ringgit
*/
protected static $currencySymbol = array(
'RM'
);
/**
* Return a Malaysian Bank
*
* @example 'Maybank'
*
* @return @string
*/
public function bank()
{
$formats = static::randomElement(static::$bankFormats);
return $this->generator->parse($formats);
}
/**
* Return a Malaysian Bank account number
*
* @example '1234567890123456'
*
* @return @string
*/
public function bankAccountNumber()
{
$formats = static::randomElement(static::$bankAccountNumberFormats);
return static::numerify($formats);
}
/**
* Return a Malaysian Local Bank
*
* @example 'Public Bank'
*
* @return @string
*/
public static function localBank()
{
return static::randomElement(static::$localBanks);
}
/**
* Return a Malaysian Foreign Bank
*
* @example 'Citibank Berhad'
*
* @return @string
*/
public static function foreignBank()
{
return static::randomElement(static::$foreignBanks);
}
/**
* Return a Malaysian Government Bank
*
* @example 'Bank Simpanan Nasional'
*
* @return @string
*/
public static function governmentBank()
{
return static::randomElement(static::$governmentBanks);
}
/**
* Return a Malaysian insurance company
*
* @example 'AIA Malaysia'
*
* @return @string
*/
public static function insurance()
{
return static::randomElement(static::$insuranceCompanies);
}
/**
* Return a Malaysian Bank SWIFT Code
*
* @example 'MBBEMYKLXXX'
*
* @return @string
*/
public static function swiftCode()
{
return static::toUpper(static::lexify(static::randomElement(static::$swiftCodes)));
}
/**
* Return the Malaysian currency symbol
*
* @example 'RM'
*
* @return @string
*/
public static function currencySymbol()
{
return static::randomElement(static::$currencySymbol);
}
}
This diff is collapsed.
<?php
namespace Faker\Provider\ms_MY;
class PhoneNumber extends \Faker\Provider\PhoneNumber
{
protected static $formats = array(
'{{mobileNumber}}',
'{{fixedLineNumber}}',
'{{voipNumber}}'
);
protected static $plusSymbol = array(
'+'
);
protected static $countryCodePrefix = array(
'6'
);
/**
* @link https://en.wikipedia.org/wiki/Telephone_numbers_in_Malaysia#Mobile_phone_codes_and_IP_telephony
*/
protected static $zeroOneOnePrefix = array('10','11','12','13','14','15','16','17','18','19','20','22','23','32');
protected static $zeroOneFourPrefix = array('2','3','4','5','6','7','8','9');
protected static $zeroOneFivePrefix = array('1','2','3','4','5','6','9');
/**
* @link https://en.wikipedia.org/wiki/Telephone_numbers_in_Malaysia#Mobile_phone_codes_and_IP_telephony
*/
protected static $mobileNumberFormatsWithFormatting = array(
'010-### ####',
'011-{{zeroOneOnePrefix}}## ####',
'012-### ####',
'013-### ####',
'014-{{zeroOneFourPrefix}}## ####',
'016-### ####',
'017-### ####',
'018-### ####',
'019-### ####',
);
protected static $mobileNumberFormats = array(
'010#######',
'011{{zeroOneOnePrefix}}######',
'012#######',
'013#######',
'014{{zeroOneFourPrefix}}######',
'016#######',
'017#######',
'018#######',
'019#######',
);
/**
* @link https://en.wikipedia.org/wiki/Telephone_numbers_in_Malaysia#Geographic_area_codes
*/
protected static $fixedLineNumberFormatsWithFormatting = array(
'03-#### ####',
'04-### ####',
'05-### ####',
'06-### ####',
'07-### ####',
'08#-## ####',
'09-### ####',
);
protected static $fixedLineNumberFormats = array(
'03########',
'04#######',
'05#######',
'06#######',
'07#######',
'08#######',
'09#######',
);
/**
* @link https://en.wikipedia.org/wiki/Telephone_numbers_in_Malaysia#Mobile_phone_codes_and_IP_telephony
*/
protected static $voipNumberWithFormatting = array(
'015-{{zeroOneFivePrefix}}## ####'
);
protected static $voipNumber = array(
'015{{zeroOneFivePrefix}}######'
);
/**
* Return a Malaysian Mobile Phone Number.
*
* @example '+6012-345-6789'
*
* @param bool $countryCodePrefix true, false
* @param bool $formatting true, false
*
* @return string
*/
public function mobileNumber($countryCodePrefix = true, $formatting = true)
{
if ($formatting) {
$format = static::randomElement(static::$mobileNumberFormatsWithFormatting);
} else {
$format = static::randomElement(static::$mobileNumberFormats);
}
if ($countryCodePrefix) {
return static::countryCodePrefix($formatting) . static::numerify($this->generator->parse($format));
} else {
return static::numerify($this->generator->parse($format));
}
}
/**
* Return prefix digits for 011 numbers
*
* @example '10'
*
* @return string
*/
public static function zeroOneOnePrefix()
{
return static::numerify(static::randomElement(static::$zeroOneOnePrefix));
}
/**
* Return prefix digits for 014 numbers
*
* @example '2'
*
* @return string
*/
public static function zeroOneFourPrefix()
{
return static::numerify(static::randomElement(static::$zeroOneFourPrefix));
}
/**
* Return prefix digits for 015 numbers
*
* @example '1'
*
* @return string
*/
public static function zeroOneFivePrefix()
{
return static::numerify(static::randomElement(static::$zeroOneFivePrefix));
}
/**
* Return a Malaysian Fixed Line Phone Number.
*
* @example '+603-4567-8912'
*
* @param bool $countryCodePrefix true, false
* @param bool $formatting true, false
*
* @return string
*/
public function fixedLineNumber($countryCodePrefix = true, $formatting = true)
{
if ($formatting) {
$format = static::randomElement(static::$fixedLineNumberFormatsWithFormatting);
} else {
$format = static::randomElement(static::$fixedLineNumberFormats);
}
if ($countryCodePrefix) {
return static::countryCodePrefix($formatting) . static::numerify($this->generator->parse($format));
} else {
return static::numerify($this->generator->parse($format));
}
}
/**
* Return a Malaysian VoIP Phone Number.
*
* @example '+6015-678-9234'
*
* @param bool $countryCodePrefix true, false
* @param bool $formatting true, false
*
* @return string
*/
public function voipNumber($countryCodePrefix = true, $formatting = true)
{
if ($formatting) {
$format = static::randomElement(static::$voipNumberWithFormatting);
} else {
$format = static::randomElement(static::$voipNumber);
}
if ($countryCodePrefix) {
return static::countryCodePrefix($formatting) . static::numerify($this->generator->parse($format));
} else {
return static::numerify($this->generator->parse($format));
}
}
/**
* Return a Malaysian Country Code Prefix.
*
* @example '+6'
*
* @param bool $formatting true, false
*
* @return string
*/
public static function countryCodePrefix($formatting = true)
{
if ($formatting) {
return static::randomElement(static::$plusSymbol) . static::randomElement(static::$countryCodePrefix);
} else {
return static::randomElement(static::$countryCodePrefix);
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
namespace Faker\Provider\sl_SI;
class Company extends \Faker\Provider\Company
{
protected static $formats = array(
'{{firstName}} {{lastName}} s.p.',
'{{lastName}} {{companySuffix}}',
'{{lastName}}, {{lastName}} in {{lastName}} {{companySuffix}}',
);
protected static $companySuffix = array('d.o.o.', 'd.d.', 'k.d.', 'k.d.d.','d.n.o.','so.p.');
}
<?php
namespace Faker\Provider\th_TH;
class Color extends \Faker\Provider\Color
{
protected static $safeColorNames = array(
'ขาว','ชมพู','ดำ','น้ำตาล','น้ำเงิน','ฟ้า','ม่วง','ส้ม','เขียว','เขียวอ่อน','เหลือง','แดง'
);
protected static $allColorNames = array(
'กากี','ขาว','คราม','ชมพู','ดำ','ทอง','นาค','น้ำตาล',
'น้ำเงิน','ฟ้า','ม่วง','ส้ม','เขียว','เขียวอ่อน',
'เงิน','เทา','เหลือง','เหลืองอ่อน','แดง','่ขี้ม้า'
);
}
<?php
namespace Faker\Provider\tr_TR;
class Company extends \Faker\Provider\Company
{
protected static $formats = array(
'{{lastName}} {{companySuffix}}',
'{{lastName}}oğlu {{companySuffix}}',
'{{lastName}} {{lastName}} {{companySuffix}}',
'{{lastName}} {{companyField}} {{companySuffix}}',
'{{lastName}} {{companyField}} {{companySuffix}}',
'{{lastName}} {{companyField}} {{companySuffix}}',
'{{lastName}} {{lastName}} {{companyField}} {{companySuffix}}',
);
protected static $companySuffix = array('A.Ş.', 'Ltd. Şti.');
protected static $companyField = array(
'Akaryakıt', 'Beyaz Eşya', 'Bilgi İşlem', 'Bilgisayar', 'Bilişim Hizmetleri',
'Biracılık ve Malt Sanayii', 'Cam Sanayii', 'Çimento', 'Demir ve Çelik',
'Dış Ticaret', 'Eczacılık', 'Elektrik İletim', 'Elektrik Üretim', 'Elektronik',
'Emlak', 'Enerji', 'Giyim', 'Gıda', 'Holding', 'Isıtma ve Soğutma Sistemleri',
'İletişim Hizmetleri', 'İnşaat ve Sanayi', 'İthalat ve İhracat', 'Kimya',
'Kurumsal Hizmetler', 'Lojistik', 'Madencilik', 'Makina', 'Mağazalar', 'Nakliyat',
'Otomotiv', 'Pazarlama', 'Perakende Ticaret', 'Petrol', 'Petrolcülük', 'Sanayi',
'Sağlık Hizmetleri', 'Servis ve Ticaret', 'Süt Ürünleri', 'Tarım Sanayi',
'Tavukçuluk', 'Tekstil', 'Telekomunikasyon', 'Tersane ve Ulaşım Sanayi',
'Ticaret', 'Ticaret ve Sanayi', 'Ticaret ve Taahhüt', 'Turizm', 'Yatırım'
);
/**
* @link https://tr.wikipedia.org/wiki/Meslekler_listesi
* @note Randomly took 300 from this list
*/
protected static $jobTitleFormat = array(
'Acil tıp teknisyeni', 'Agronomist', 'Aile hekimi', 'Aktar', 'Aktör', 'Aktüer',
'Akustikçi', 'Albay', 'Ambarcı', 'Ambulans şoförü', 'Amiral', 'Analist',
'Antika satıcısı', 'Araba tamircisi', 'Arabacı', 'Araştırmacı', 'Armatör', 'Artist',
'Asker', 'Astrofizikçi', 'Astrolog', 'Astronom', 'Astronot', 'Atlet', 'Avukat',
'Ayakkabı boyacısı', 'Ayakkabı tamircisi', 'Ayakçı', 'Ağ yöneticisi', 'Aşçıbaşı',
'Bacacı', 'Badanacı', 'Baharatçı', 'Bahçe bitkileri uzmanı', 'Bakkal', 'Bakteriyolog',
'Balon pilotu', 'Bankacı', 'Banker', 'Barmeyd', 'Başdümenci', 'Başpiskopos',
'Başçavuş', 'Bebek Bakıcısı', 'Belediye başkanı', 'Belediye meclisi üyesi', 'Besteci',
'Biletçi', 'Bilgi İşlemci', 'Bilgisayar mühendisi', 'Binicilik', 'Biyografi yazarı',
'Bobinajcı', 'Borsacı', 'Boyacı', 'Bulaşıkçı', 'Börekç', 'Çamaşırcı', 'Çantacı',
'Çevik Kuvvet', 'Çevirmen', 'Çevre Mühendisi', 'Çevrebilimci', 'Çeyizci',
'Çiftlik işletici', 'Çiftçi', 'Çinici', 'Çoban', 'Çırak', 'Dadı', 'Daktilograf',
'Dalgıç', 'Dansöz', 'Dedektif', 'Derici', 'Değirmen işçisi', 'Değirmenci', 'Dilci',
'Diplomat', 'Doktor', 'Dokumacı', 'Dondurmacı', 'Doğramacı', 'Dövizci', 'Döşemeci',
'Elektrik mühendisi', 'Elektronik mühendisi', 'Elektronik ve Haberleşme mühendisi',
'Embriyolog', 'Emniyet amiri', 'Emniyet genel müdürü', 'Ergonomist', 'Eskici', 'Fahişe',
'Fizikçi', 'Fizyoterapist', 'Fotoğrafçı', 'Fıçıcı', 'Galerici', 'Garson',
'Gazete dağıtıcısı', 'Gazete satıcısı', 'Gazeteci', 'Gelir uzman yardımcısı', 'General',
'Genetik mühendisi', 'Gezici vaiz', 'Gondolcu', 'Guru', 'Gökbilimci', 'Gözlükçü',
'Güfteci', 'Gümrük uzmanı', 'Haham', 'Hakem', 'Halkbilimci', 'Hamal', 'Hamurkâr',
'Hareket memuru', 'Hava trafikçisi', 'Havacı', 'Hayvan terbiyecisi', 'Hesap uzmanı',
'Heykeltıraş', 'Hokkabaz', 'Irgat', 'İcra memuru', 'İllüzyonist', 'İmam',
'İnsan kaynakları uzmanı', 'İplikçi', 'İthalatçı', 'İş ve uğraşı terapisti', 'İşaretçi',
'Jimnastikçi', 'Jokey', 'Kabin görevlisi', 'Kabuk soyucusu', 'Kadın berberi', 'Kahveci',
'Kalaycı', 'Kaplamacı', 'Kapı satıcısı', 'Kardinal', 'Kardiyolog', 'Karikatürist',
'Kat görevlisi', 'Kaymakam', 'Kayıkçı', 'Kazıcı', 'Klarnetçi', 'Konserveci',
'Konveyör operatörü', 'Koramiral', 'Korgeneral', 'Kozmolog', 'Kuaför', 'Kumaşçı', 'Kumcu',
'Kuruyemişçi', 'Kurye', 'Kuyumcu', 'Kâğıtçı', 'Köpek eğiticisi', 'Köşe yazarı', 'Kürkçü',
'Kırtasiyeci', 'Laborant', 'Laboratuar işçisi', 'Lahmacuncu', 'Lehimci', 'Levazımcı',
'Lobici', 'Lokantacı', 'Lokman', 'Lostracı', 'Madenci', 'Makastar', 'Makine mühendisi',
'Makine zabiti', 'Makyajcı', 'Mali hizmetler uzmanı', 'Manastır baş rahibesi',
'Manifaturacı', 'Manikürcü', 'Masör', 'Matematikçi', 'Memur', 'Mermerci',
'Meteoroloji uzmanı', 'Misyoner', 'Model', 'Modelci', 'Modelist', 'Montajcı', 'Montör',
'Muallim', 'Muhafız', 'Mumyalayıcı', 'Müzik yönetmeni', 'Müşavir', 'Nalbant', 'Nalbur',
'Oduncu', 'Orgcu', 'Ornitolog', 'Oto elektrikçisi', 'Oto lastik tamircisi', 'Oyuncakçı',
'Oyuncu', 'Ön muhasebe yardımcı elemanı', 'Ön muhasebeci', 'Öğretim elemanı',
'Öğretim görevlisi', 'Öğretim üyesi', 'Papaz', 'Paramedik', 'Pastörizör', 'Pencereci',
'Perukçu', 'Peyzaj teknikeri', 'Peçeteci', 'Pideci', 'Pilot', 'Piyanist', 'Politikacı',
'Pompacı', 'Psikolog', 'Radyolog', 'Radyoloji teknisyeni/teknikeri', 'Rejisör',
'Reklamcı', 'Rektör', 'Rot balansçı', 'Saat tamircisi', 'Sanat yönetmeni', 'Saraç',
'Saz şairi', 'Sekreter', 'Ses teknisyeni', 'Sicil memuru', 'Sihirbaz', 'Sistem mühendisi',
'Sosyal hizmet uzmanı', 'Sosyolog', 'Soğuk demirci', 'Stenograf', 'Stilist', 'Striptizci',
'Sucu', 'Sunucu', 'Susuz araç yıkama', 'Sünnetçi', 'Sürveyan', 'Şapel papazı',
'Şarkı sözü yazarı', 'Şehir Plancısı', 'Şekerci', 'Şimşirci', 'Şoför', 'Tahsildar',
'Tarihçi', 'Tasarımcı', 'Taşlayıcı', 'Taşçı', 'Tekniker', 'Teknisyen', 'Teknoloji uzmani',
'Televizyon tamircisi', 'Terapist', 'Tesisatçı', 'Teşrifatçı', 'Tornacı', 'Tuğgeneral',
'Ulaşım sorumlusu', 'Ustabaşı', 'Uydu antenci', 'Üst Düzey Yönetici', 'Ütücü',
'Uzay bilimcisi', 'Vali', 'Veri hazırlama ve kontrol işletmeni', 'Veteriner hekim',
'Veteriner sağlık teknikeri', 'Veznedar', 'Vinç operatörü', 'Vitrinci', 'Yarbay',
'Yardımcı pilot', 'Yargıç', 'Yazar', 'Yazı işleri müdürü', 'Yazılım mühendisi',
'Yer gösterici', 'Yol bekçisi', 'Yorgancı', 'Yoğurtçu', 'Yıkıcı', 'Zabıta', 'Zoolog'
);
/**
* Returns a random company field.
*
* @return string
*/
public static function companyField()
{
return static::randomElement(static::$companyField);
}
}
<?php
namespace Faker\Test\Calculator;
use Faker\Calculator\TCNo;
use PHPUnit\Framework\TestCase;
class TCNoTest extends TestCase
{
public function checksumProvider()
{
return array(
array('553006348', '82'),
array('350630743', '78'),
array('550600932', '88'),
array('487932947', '70'),
array('168113862', '40')
);
}
/**
* @dataProvider checksumProvider
* @param $tcNo
* @param $checksum
*/
public function testChecksum($tcNo, $checksum)
{
$this->assertEquals($checksum, TCNo::checksum($tcNo), $tcNo);
}
public function validatorProvider()
{
return array(
array('22978160678', true),
array('26480045324', true),
array('47278360658', true),
array('34285002510', true),
array('19874561012', true),
array('11111111111', false),
array('11234567899', false),
);
}
/**
* @dataProvider validatorProvider
* @param $tcNo
* @param $isValid
*/
public function testIsValid($tcNo, $isValid)
{
$this->assertEquals($isValid, TCNo::isValid($tcNo), $tcNo);
}
}
<?php
namespace Faker\Test\Provider\el_GR;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\el_GR\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ '))
);
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ—'))
);
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ,'))
);
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ! '))
);
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ; '))
);
$this->assertSame(
'Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Και δεν άκουσες το κλοπακλόπ, κλοπακλόπ, κλοπακλόπ: '))
);
}
}
<?php
namespace Faker\Test\Provider\en_US;
use Faker\Provider\en_US\Company;
use Faker\Generator;
class CompanyTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Company($faker));
$this->faker = $faker;
}
/**
* @link https://stackoverflow.com/questions/4242433/regex-for-ein-number-and-ssn-number-format-in-jquery/35471665#35471665
*/
public function testEin()
{
$number = $this->faker->ein;
// should be in the format ##-#######, with a valid prefix
$this->assertRegExp('/^(0[1-6]||1[0-6]|2[0-7]|[35]\d|[468][0-8]|7[1-7]|9[0-58-9])-\d{7}$/', $number);
}
}
<?php
/**
* Created by Domingo Oropeza <dioh_@hotmail.com> for Faker
* Date: 01/09/2017
* Time: 09:45 PM
*/
namespace Faker\Test\Provider\es_VE;
use Faker\Generator;
use Faker\Provider\es_VE\Company;
use PHPUnit\Framework\TestCase;
class CompanyTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->seed(1);
$faker->addProvider(new Company($faker));
$this->faker = $faker;
}
/**
* national Id format validator
*/
public function testNationalId()
{
$pattern = '/^[VJGECP]-?\d{8}-?\d$/';
$rif = $this->faker->taxpayerIdentificationNumber;
$this->assertRegExp($pattern, $rif);
$rif = $this->faker->taxpayerIdentificationNumber('-');
$this->assertRegExp($pattern, $rif);
}
}
<?php
/**
* Created by Domingo Oropeza for Faker
* Date: 01/09/2017
* Time: 11:02 PM
*/
namespace Faker\Test\Provider\es_VE;
use Faker\Generator;
use Faker\Provider\es_VE\Person;
use PHPUnit\Framework\TestCase;
class PersonTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->seed(1);
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
/**
* national Id format validator
*/
public function testNationalId()
{
$pattern = '/(?:^V-?\d{5,9}$)|(?:^E-?\d{8,9}$)/';
$cedula = $this->faker->nationalId;
$this->assertRegExp($pattern, $cedula);
$cedula = $this->faker->nationalId('-');
$this->assertRegExp($pattern, $cedula);
}
}
<?php
namespace Faker\Test\Provider\fr_FR;
use Faker\Generator;
use Faker\Provider\fr_FR\Address;
use PHPUnit\Framework\TestCase;
class AddressTest extends TestCase
{
/**
* @var Faker\Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Address($faker));
$this->faker = $faker;
}
/**
* @test
*/
public function testSecondaryAddress()
{
$secondaryAdress = $this->faker->secondaryAddress();
$this->assertNotEmpty($secondaryAdress);
$this->assertInternalType('string', $secondaryAdress);
}
}
<?php
namespace Faker\Test\Provider\fr_FR;
use Faker\Calculator\Luhn;
use Faker\Generator;
use Faker\Provider\fr_FR\Payment;
use PHPUnit\Framework\TestCase;
class PaymentTest extends TestCase
{
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Payment($faker));
$this->faker = $faker;
}
public function testFormattedVat()
{
$vat = $this->faker->vat(true);
$this->assertRegExp("/^FR\s\w{2}\s\d{3}\s\d{3}\s\d{3}$/", $vat);
$vat = str_replace(' ', '', $vat);
$siren = substr($vat, 4, 12);
$this->assertTrue(Luhn::isValid($siren));
$key = (int) substr($siren, 2, 2);
if ($key === 0) {
$this->assertEqual($key, (12 + 3 * ($siren % 97)) % 97);
}
}
public function testUnformattedVat()
{
$vat = $this->faker->vat(false);
$this->assertRegExp("/^FR\w{2}\d{9}$/", $vat);
$siren = substr($vat, 4, 12);
$this->assertTrue(Luhn::isValid($siren));
$key = (int) substr($siren, 2, 2);
if ($key === 0) {
$this->assertEqual($key, (12 + 3 * ($siren % 97)) % 97);
}
}
}
\ No newline at end of file
<?php
namespace Faker\Test\Provider\fr_FR;
use Faker\Generator;
use Faker\Provider\fr_FR\PhoneNumber;
class PhoneNumberTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new PhoneNumber($faker));
$this->faker = $faker;
}
public function testMobileNumber()
{
$mobileNumber = $this->faker->mobileNumber();
$this->assertRegExp('/^(\+33 |\+33 \(0\)|0)(6|7)(?:(\s{1})?\d{2}){4}$/', $mobileNumber);
}
public function testMobileNumber07Format()
{
$mobileNumberFormat = $this->faker->phoneNumber07();
$this->assertRegExp('/^([3-9]{1})\d(\d{2}){3}$/', $mobileNumberFormat);
}
public function testMobileNumber07WithSeparatorFormat()
{
$mobileNumberFormat = $this->faker->phoneNumber07WithSeparator();
$this->assertRegExp('/^([3-9]{1})\d( \d{2}){3}$/', $mobileNumberFormat);
}
public function testServiceNumber()
{
$serviceNumber = $this->faker->serviceNumber();
$this->assertRegExp('/^(\+33 |\+33 \(0\)|0)8(?:(\s{1})?\d{2}){4}$/', $serviceNumber);
}
public function testServiceNumberFormat()
{
$serviceNumberFormat = $this->faker->phoneNumber08();
$this->assertRegExp('/^((0|1|2)\d{1}|9[^46])\d{6}$/', $serviceNumberFormat);
}
public function testServiceNumberWithSeparatorFormat()
{
$serviceNumberFormat = $this->faker->phoneNumber08WithSeparator();
$this->assertRegExp('/^((0|1|2)\d{1}|9[^46])( \d{2}){3}$/', $serviceNumberFormat);
}
}
<?php
namespace Faker\Test\Provider\fr_FR;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\fr_FR\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'Que faisaient-elles maintenant? À.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À '))
);
$this->assertSame(
'Que faisaient-elles maintenant? À.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À— '))
);
$this->assertSame(
'Que faisaient-elles maintenant? À.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À,'))
);
$this->assertSame(
'Que faisaient-elles maintenant? À!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À! '))
);
$this->assertSame(
'Que faisaient-elles maintenant? À.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À: '))
);
$this->assertSame(
'Que faisaient-elles maintenant? À.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Que faisaient-elles maintenant? À; '))
);
}
}
<?php
namespace Faker\Test\Provider\ka_GE;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\el_GR\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე '))
);
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე— '))
);
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე, '))
);
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე! '))
);
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე; '))
);
$this->assertSame(
'ჭეშმარიტია. ჩვენც ისე.',
$this->getMethod('appendEnd')->invokeArgs(null, array('ჭეშმარიტია. ჩვენც ისე: '))
);
}
}
<?php
namespace Faker\Test\Provider\kk_KZ;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\kk_KZ\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар '))
);
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар— '))
);
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар, '))
);
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар! '))
);
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар: '))
);
$this->assertSame(
'Арыстан баб кесенесі - көне Отырар.',
$this->getMethod('appendEnd')->invokeArgs(null, array('Арыстан баб кесенесі - көне Отырар; '))
);
}
}
<?php
namespace Faker\Test\Provider\ko_KR;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\el_GR\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가 '))
);
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가—'))
);
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가,'))
);
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가! '))
);
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가: '))
);
$this->assertSame(
'최석(崔晳)으로부터 최후의 편지가.',
$this->getMethod('appendEnd')->invokeArgs(null, array('최석(崔晳)으로부터 최후의 편지가; '))
);
}
}
<?php
namespace Faker\Test\Provider\ms_MY;
use Faker\Generator;
use Faker\Provider\ms_MY\Person;
use PHPUnit\Framework\TestCase;
class PersonTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
/**
* @link https://en.wikipedia.org/wiki/Malaysian_identity_card#Structure_of_the_National_Registration_Identity_Card_Number_(NRIC)
*/
public function testPersonalIdentityCardNumber()
{
$myKadNumber = $this->faker->myKadNumber;
$yy = substr($myKadNumber, 0, 2);
//match any year from 00-99
$this->assertRegExp("/^[0-9]{2}$/", $yy);
$mm = substr($myKadNumber, 2, 2);
//match any month from 01-12
$this->assertRegExp("/^0[1-9]|1[0-2]$/", $mm);
$dd = substr($myKadNumber, 4, 2);
//match any date from 01-31
$this->assertRegExp("/^0[1-9]|1[0-9]|2[0-9]|3[0-1]$/", $dd);
$pb = substr($myKadNumber, 6, 2);
//match any valid place of birth code from 01-59 except 17-20
$this->assertRegExp("/^(0[1-9]|1[0-6])|(2[1-9]|3[0-9]|4[0-9]|5[0-9])$/", $pb);
$nnnn = substr($myKadNumber, 8, 4);
//match any number from 0000-9999
$this->assertRegExp("/^[0-9]{4}$/", $nnnn);
}
}
<?php
namespace Faker\Test\Provider\nl_BE;
use Faker\Generator;
use Faker\Provider\nl_BE\Person;
use PHPUnit\Framework\TestCase;
use Datetime;
/**
* @group Person
*/
class PersonTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
public function testRrnIsValid()
{
$rrn = $this->faker->rrn();
$this->assertEquals(11, strlen($rrn));
$ctrlNumber = substr($rrn, 9, 2);
$calcCtrl = 97 - (substr($rrn, 0, 9) % 97);
$altcalcCtrl = 97 - ((2 . substr($rrn, 0, 9)) % 97);
$this->assertContains($ctrlNumber, array($calcCtrl, $altcalcCtrl));
$middle = substr($rrn, 6, 3);
$this->assertGreaterThan(1, $middle);
$this->assertLessThan(997, $middle);
}
public function testRrnIsMale()
{
$rrn = $this->faker->rrn('male');
$this->assertEquals(substr($rrn, 6, 3) % 2, 1);
}
public function testRrnIsFemale()
{
$rrn = $this->faker->rrn('female');
$this->assertEquals(substr($rrn, 6, 3) % 2, 0);
}
}
<?php
namespace Faker\Test\Provider\nl_NL;
use Faker\Generator;
use Faker\Provider\nl_NL\Person;
use PHPUnit\Framework\TestCase;
class PersonTest extends TestCase
{
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
public function testGenerateValidIdNumber()
{
$idNumber = $this->faker->idNumber();
$this->assertEquals(9, strlen($idNumber));
$sum = -1 * $idNumber % 10;
for ($multiplier = 2; $idNumber > 0; $multiplier++) {
$val = ($idNumber /= 10) % 10;
$sum += $multiplier * $val;
}
$this->assertTrue($sum != 0 && $sum % 11 == 0);
}
}
<?php
namespace Faker\Provider\pl_PL;
use DateTime;
use Faker\Generator;
use PHPUnit\Framework\TestCase;
class PersonTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
public function testPeselLenght()
{
$pesel = $this->faker->pesel();
$this->assertEquals(11, strlen($pesel));
}
public function testPeselDate()
{
$date = new DateTime('1990-01-01');
$pesel = $this->faker->pesel($date);
$this->assertEquals('90', substr($pesel, 0, 2));
$this->assertEquals('01', substr($pesel, 2, 2));
$this->assertEquals('01', substr($pesel, 4, 2));
}
public function testPeselDateWithYearAfter2000()
{
$date = new DateTime('2001-01-01');
$pesel = $this->faker->pesel($date);
$this->assertEquals('01', substr($pesel, 0, 2));
$this->assertEquals('21', substr($pesel, 2, 2));
$this->assertEquals('01', substr($pesel, 4, 2));
}
public function testPeselDateWithYearAfter2100()
{
$date = new DateTime('2101-01-01');
$pesel = $this->faker->pesel($date);
$this->assertEquals('01', substr($pesel, 0, 2));
$this->assertEquals('41', substr($pesel, 2, 2));
$this->assertEquals('01', substr($pesel, 4, 2));
}
public function testPeselDateWithYearAfter2200()
{
$date = new DateTime('2201-01-01');
$pesel = $this->faker->pesel($date);
$this->assertEquals('01', substr($pesel, 0, 2));
$this->assertEquals('61', substr($pesel, 2, 2));
$this->assertEquals('01', substr($pesel, 4, 2));
}
public function testPeselDateWithYearBefore1900()
{
$date = new DateTime('1801-01-01');
$pesel = $this->faker->pesel($date);
$this->assertEquals('01', substr($pesel, 0, 2));
$this->assertEquals('81', substr($pesel, 2, 2));
$this->assertEquals('01', substr($pesel, 4, 2));
}
public function testPeselSex()
{
$male = $this->faker->pesel(null, 'M');
$female = $this->faker->pesel(null, 'F');
$this->assertEquals(1, $male[9] % 2);
$this->assertEquals(0, $female[9] % 2);
}
public function testPeselCheckSum()
{
$pesel = $this->faker->pesel();
$weights = array(1, 3, 7, 9, 1, 3, 7, 9, 1, 3, 1);
$sum = 0;
foreach ($weights as $key => $weight) {
$sum += $pesel[$key] * $weight;
}
$this->assertEquals(0, $sum % 10);
}
}
<?php
namespace Faker\Test\Provider\ru_RU;
use PHPUnit\Framework\TestCase;
class TextTest extends TestCase
{
private $textClass;
public function setUp()
{
$this->textClass = new \ReflectionClass('Faker\Provider\ru_RU\Text');
}
protected function getMethod($name) {
$method = $this->textClass->getMethod($name);
$method->setAccessible(true);
return $method;
}
/** @test */
function testItShouldAppendEndPunctToTheEndOfString()
{
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер '))
);
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер—'))
);
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер,'))
);
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер!.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер! '))
);
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер; '))
);
$this->assertSame(
'На другой день Чичиков отправился на обед и вечер.',
$this->getMethod('appendEnd')->invokeArgs(null, array('На другой день Чичиков отправился на обед и вечер: '))
);
}
}
<?php
namespace Faker\Test\Provider\tr_TR;
use Faker\Provider\tr_TR\Company;
use Faker\Generator;
class CompanyTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Company($faker));
$this->faker = $faker;
}
public function testCompany()
{
$company = $this->faker->companyField;
$this->assertNotNull($company);
}
}
<?php
namespace Faker\Provider\tr_TR;
use Faker\Generator;
use PHPUnit\Framework\TestCase;
class PaymentTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Payment($faker));
$this->faker = $faker;
}
public function testBankAccountNumber()
{
$accNo = $this->faker->bankAccountNumber;
$this->assertEquals(substr($accNo, 0, 2), 'TR');
$this->assertEquals(26, strlen($accNo));
}
}
<?php
namespace Faker\Test\Provider\tr_TR;
use Faker\Calculator\TCNo;
use Faker\Provider\tr_TR\Person;
use Faker\Generator;
use PHPUnit\Framework\TestCase;
class PersonTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new Person($faker));
$this->faker = $faker;
}
public function testTCNo()
{
for ($i = 0; $i < 100; $i++) {
$number = $this->faker->tcNo;
$this->assertEquals(11, strlen($number));
$this->assertTrue(TCNo::isValid($number));
}
}
}
<?php
namespace Faker\Test\Provider\tr_TR;
use Faker\Generator;
use Faker\Provider\tr_TR\PhoneNumber;
use PHPUnit\Framework\TestCase;
class PhoneNumberTest extends TestCase
{
/**
* @var Generator
*/
private $faker;
public function setUp()
{
$faker = new Generator();
$faker->addProvider(new PhoneNumber($faker));
$this->faker = $faker;
}
public function testPhoneNumber()
{
for ($i = 0; $i < 100; $i++) {
$number = $this->faker->phoneNumber;
$baseNumber = preg_replace('/ *x.*$/', '', $number); // Remove possible extension
$digits = array_values(array_filter(str_split($baseNumber), 'ctype_digit'));
$this->assertGreaterThan(10, count($digits));
}
}
}
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'Select date' => 'Күнін таңдау',
'Clear field' => 'Тазарту',
];
<?php
/**
* Message translations.
*
* This file is automatically generated by 'yii message' command.
* It contains the localizable messages extracted from source code.
* You may modify this file by translating the extracted messages.
*
* Each array element represents the translation (value) of a message (key).
* If the value is empty, the message is considered as not translated.
* Messages that no longer need translation will have their translations
* enclosed between a pair of '@@' marks.
*
* Message string can be used with plural forms format. Check i18n section
* of the guide for details.
*
* NOTE: this file must be saved in UTF-8 encoding.
*/
return [
'Clear field' => 'Tyhjennä kenttä',
'Select date' => 'Valitse päivämäärä',
];
\ No newline at end of file
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Email address encoder.
*
* @author Christian Schmidt
*/
interface Swift_AddressEncoder
{
/**
* Encodes an email address.
*
* @throws Swift_AddressEncoderException If the email cannot be represented in
* the encoding implemented by this class.
*/
public function encodeString(string $address): string;
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An IDN email address encoder.
*
* Encodes the domain part of an address using IDN. This is compatible will all
* SMTP servers.
*
* This encoder does not support email addresses with non-ASCII characters in
* local-part (the substring before @). To send to such addresses, use
* Swift_AddressEncoder_Utf8AddressEncoder together with
* Swift_Transport_Esmtp_SmtpUtf8Handler. Your outbound SMTP server must support
* the SMTPUTF8 extension.
*
* @author Christian Schmidt
*/
class Swift_AddressEncoder_IdnAddressEncoder implements Swift_AddressEncoder
{
/**
* Encodes the domain part of an address using IDN.
*
* @throws Swift_AddressEncoderException If local-part contains non-ASCII characters,
* or if no suitable IDN encoder is installed.
*/
public function encodeString(string $address): string
{
$i = strrpos($address, '@');
if (false !== $i) {
$local = substr($address, 0, $i);
$domain = substr($address, $i + 1);
if (preg_match('/[^\x00-\x7F]/', $local)) {
throw new Swift_AddressEncoderException('Non-ASCII characters not supported in local-part', $address);
}
if (preg_match('/[^\x00-\x7F]/', $domain)) {
$address = sprintf('%s@%s', $local, $this->idnToAscii($domain));
}
}
return $address;
}
/**
* IDN-encodes a UTF-8 string to ASCII.
*/
protected function idnToAscii(string $string): string
{
if (function_exists('idn_to_ascii')) {
return idn_to_ascii($string, 0, INTL_IDNA_VARIANT_UTS46);
}
if (class_exists('TrueBV\Punycode')) {
$punycode = new \TrueBV\Punycode();
return $punycode->encode($string);
}
throw new Swift_AddressEncoderException('Non-ASCII characters in address, but no IDN encoder found (install the intl extension or the true/punycode package)', $address);
}
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* A UTF-8 email address encoder.
*
* Returns the email address verbatimly in UTF-8 as permitted by RFC 6531 and
* RFC 6532. It supports addresses containing non-ASCII characters in both
* local-part and domain (i.e. on both sides of @).
*
* This encoder must be used together with Swift_Transport_Esmtp_SmtpUtf8Handler
* and requires that the outbound SMTP server supports the SMTPUTF8 extension.
*
* If your outbound SMTP server does not support SMTPUTF8, use
* Swift_AddressEncoder_IdnAddressEncoder instead. This allows sending to email
* addresses with non-ASCII characters in the domain, but not in local-part.
*
* @author Christian Schmidt
*/
class Swift_AddressEncoder_Utf8AddressEncoder implements Swift_AddressEncoder
{
/**
* Returns the address verbatimly.
*/
public function encodeString(string $address): string
{
return $address;
}
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* AddressEncoderException when the specified email address is in a format that
* cannot be encoded by a given address encoder.
*
* @author Christian Schmidt
*/
class Swift_AddressEncoderException extends Swift_RfcComplianceException
{
protected $address;
public function __construct(string $message, string $address)
{
parent::__construct($message);
$this->address = $address;
}
public function getAddress(): string
{
return $this->address;
}
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2004-2009 Chris Corbyn
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Handles the case where the email body is already encoded and you just need specify the correct
* encoding without actually changing the encoding of the body.
*
* @author Jan Flora <jf@penneo.com>
*/
class Swift_Mime_ContentEncoder_NullContentEncoder implements Swift_Mime_ContentEncoder
{
/**
* The name of this encoding scheme (probably 7bit or 8bit).
*
* @var string
*/
private $_name;
/**
* Creates a new NullContentEncoder with $name (probably 7bit or 8bit).
*
* @param string $name
*/
public function __construct($name)
{
$this->_name = $name;
}
/**
* Encode a given string to produce an encoded string.
*
* @param string $string
* @param int $firstLineOffset ignored
* @param int $maxLineLength ignored
*
* @return string
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
{
return $string;
}
/**
* Encode stream $in to stream $out.
*
* @param int $firstLineOffset ignored
* @param int $maxLineLength ignored
*/
public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
{
while (false !== ($bytes = $os->read(8192))) {
$is->write($bytes);
}
}
/**
* Get the name of this encoding scheme.
*
* @return string
*/
public function getName()
{
return $this->_name;
}
/**
* Not used.
*/
public function charsetChanged($charset)
{
}
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An ESMTP handler for 8BITMIME support (RFC 6152).
*
* 8BITMIME is required when sending 8-bit content to over SMTP, e.g. when using
* Swift_Mime_ContentEncoder_PlainContentEncoder in "8bit" mode.
*
* 8BITMIME mode is enabled unconditionally, even when sending ASCII-only
* messages, so it should only be used with an outbound SMTP server that will
* convert the message to 7-bit MIME if the next hop does not support 8BITMIME.
*
* @author Christian Schmidt
*/
class Swift_Transport_Esmtp_EightBitMimeHandler implements Swift_Transport_EsmtpHandler
{
protected $encoding;
/**
* @param string $encoding The parameter so send with the MAIL FROM command;
* either "8BITMIME" or "7BIT"
*/
public function __construct(string $encoding = '8BITMIME')
{
$this->encoding = $encoding;
}
/**
* Get the name of the ESMTP extension this handles.
*
* @return string
*/
public function getHandledKeyword()
{
return '8BITMIME';
}
/**
* Not used.
*/
public function setKeywordParams(array $parameters)
{
}
/**
* Not used.
*/
public function afterEhlo(Swift_Transport_SmtpAgent $agent)
{
}
/**
* Get params which are appended to MAIL FROM:<>.
*
* @return string[]
*/
public function getMailParams()
{
return ['BODY='.$this->encoding];
}
/**
* Not used.
*/
public function getRcptParams()
{
return [];
}
/**
* Not used.
*/
public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
{
}
/**
* Returns +1, -1 or 0 according to the rules for usort().
*
* This method is called to ensure extensions can be execute in an appropriate order.
*
* @param string $esmtpKeyword to compare with
*
* @return int
*/
public function getPriorityOver($esmtpKeyword)
{
return 0;
}
/**
* Not used.
*/
public function exposeMixinMethods()
{
return [];
}
/**
* Not used.
*/
public function resetState()
{
}
}
<?php
/*
* This file is part of SwiftMailer.
* (c) 2018 Christian Schmidt
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* An ESMTP handler for SMTPUTF8 support (RFC 6531).
*
* SMTPUTF8 is required when sending to email addresses containing non-ASCII
* characters in local-part (the substring before @). This handler should be
* used together with Swift_AddressEncoder_Utf8AddressEncoder.
*
* SMTPUTF8 mode is enabled unconditionally, even when sending to ASCII-only
* addresses, so it should only be used with an outbound SMTP server that will
* deliver ASCII-only messages even if the next hop does not support SMTPUTF8.
*
* @author Christian Schmidt
*/
class Swift_Transport_Esmtp_SmtpUtf8Handler implements Swift_Transport_EsmtpHandler
{
public function __construct()
{
}
/**
* Get the name of the ESMTP extension this handles.
*
* @return string
*/
public function getHandledKeyword()
{
return 'SMTPUTF8';
}
/**
* Not used.
*/
public function setKeywordParams(array $parameters)
{
}
/**
* Not used.
*/
public function afterEhlo(Swift_Transport_SmtpAgent $agent)
{
}
/**
* Get params which are appended to MAIL FROM:<>.
*
* @return string[]
*/
public function getMailParams()
{
return ['SMTPUTF8'];
}
/**
* Not used.
*/
public function getRcptParams()
{
return [];
}
/**
* Not used.
*/
public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
{
}
/**
* Returns +1, -1 or 0 according to the rules for usort().
*
* This method is called to ensure extensions can be execute in an appropriate order.
*
* @param string $esmtpKeyword to compare with
*
* @return int
*/
public function getPriorityOver($esmtpKeyword)
{
return 0;
}
/**
* Not used.
*/
public function exposeMixinMethods()
{
return [];
}
/**
* Not used.
*/
public function resetState()
{
}
}
vendor/
composer.lock
phpunit.xml
CHANGELOG
=========
4.1.0
-----
* added the `Process::isTtySupported()` method that allows to check for TTY support
* made `PhpExecutableFinder` look for the `PHP_BINARY` env var when searching the php binary
* added the `ProcessSignaledException` class to properly catch signaled process errors
4.0.0
-----
* environment variables will always be inherited
* added a second `array $env = array()` argument to the `start()`, `run()`,
`mustRun()`, and `restart()` methods of the `Process` class
* added a second `array $env = array()` argument to the `start()` method of the
`PhpProcess` class
* the `ProcessUtils::escapeArgument()` method has been removed
* the `areEnvironmentVariablesInherited()`, `getOptions()`, and `setOptions()`
methods of the `Process` class have been removed
* support for passing `proc_open()` options has been removed
* removed the `ProcessBuilder` class, use the `Process` class instead
* removed the `getEnhanceWindowsCompatibility()` and `setEnhanceWindowsCompatibility()` methods of the `Process` class
* passing a not existing working directory to the constructor of the `Symfony\Component\Process\Process` class is not
supported anymore
3.4.0
-----
* deprecated the ProcessBuilder class
* deprecated calling `Process::start()` without setting a valid working directory beforehand (via `setWorkingDirectory()` or constructor)
3.3.0
-----
* added command line arrays in the `Process` class
* added `$env` argument to `Process::start()`, `run()`, `mustRun()` and `restart()` methods
* deprecated the `ProcessUtils::escapeArgument()` method
* deprecated not inheriting environment variables
* deprecated configuring `proc_open()` options
* deprecated configuring enhanced Windows compatibility
* deprecated configuring enhanced sigchild compatibility
2.5.0
-----
* added support for PTY mode
* added the convenience method "mustRun"
* deprecation: Process::setStdin() is deprecated in favor of Process::setInput()
* deprecation: Process::getStdin() is deprecated in favor of Process::getInput()
* deprecation: Process::setInput() and ProcessBuilder::setInput() do not accept non-scalar types
2.4.0
-----
* added the ability to define an idle timeout
2.3.0
-----
* added ProcessUtils::escapeArgument() to fix the bug in escapeshellarg() function on Windows
* added Process::signal()
* added Process::getPid()
* added support for a TTY mode
2.2.0
-----
* added ProcessBuilder::setArguments() to reset the arguments on a builder
* added a way to retrieve the standard and error output incrementally
* added Process:restart()
2.1.0
-----
* added support for non-blocking processes (start(), wait(), isRunning(), stop())
* enhanced Windows compatibility
* added Process::getExitCodeText() that returns a string representation for
the exit code returned by the process
* added ProcessBuilder
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
/**
* Marker Interface for the Process Component.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
/**
* InvalidArgumentException for the Process Component.
*
* @author Romain Neutron <imprec@gmail.com>
*/
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
/**
* LogicException for the Process Component.
*
* @author Romain Neutron <imprec@gmail.com>
*/
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
use Symfony\Component\Process\Process;
/**
* Exception for failed processes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ProcessFailedException extends RuntimeException
{
private $process;
public function __construct(Process $process)
{
if ($process->isSuccessful()) {
throw new InvalidArgumentException('Expected a failed process, but the given process was successful.');
}
$error = sprintf('The command "%s" failed.'."\n\nExit Code: %s(%s)\n\nWorking directory: %s",
$process->getCommandLine(),
$process->getExitCode(),
$process->getExitCodeText(),
$process->getWorkingDirectory()
);
if (!$process->isOutputDisabled()) {
$error .= sprintf("\n\nOutput:\n================\n%s\n\nError Output:\n================\n%s",
$process->getOutput(),
$process->getErrorOutput()
);
}
parent::__construct($error);
$this->process = $process;
}
public function getProcess()
{
return $this->process;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
use Symfony\Component\Process\Process;
/**
* Exception that is thrown when a process has been signaled.
*
* @author Sullivan Senechal <soullivaneuh@gmail.com>
*/
final class ProcessSignaledException extends RuntimeException
{
private $process;
public function __construct(Process $process)
{
$this->process = $process;
parent::__construct(sprintf('The process has been signaled with signal "%s".', $process->getTermSignal()));
}
public function getProcess(): Process
{
return $this->process;
}
public function getSignal(): int
{
return $this->getProcess()->getTermSignal();
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
use Symfony\Component\Process\Process;
/**
* Exception that is thrown when a process times out.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ProcessTimedOutException extends RuntimeException
{
const TYPE_GENERAL = 1;
const TYPE_IDLE = 2;
private $process;
private $timeoutType;
public function __construct(Process $process, int $timeoutType)
{
$this->process = $process;
$this->timeoutType = $timeoutType;
parent::__construct(sprintf(
'The process "%s" exceeded the timeout of %s seconds.',
$process->getCommandLine(),
$this->getExceededTimeout()
));
}
public function getProcess()
{
return $this->process;
}
public function isGeneralTimeout()
{
return self::TYPE_GENERAL === $this->timeoutType;
}
public function isIdleTimeout()
{
return self::TYPE_IDLE === $this->timeoutType;
}
public function getExceededTimeout()
{
switch ($this->timeoutType) {
case self::TYPE_GENERAL:
return $this->process->getTimeout();
case self::TYPE_IDLE:
return $this->process->getIdleTimeout();
default:
throw new \LogicException(sprintf('Unknown timeout type "%d".', $this->timeoutType));
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Exception;
/**
* RuntimeException for the Process Component.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process;
/**
* Generic executable finder.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ExecutableFinder
{
private $suffixes = array('.exe', '.bat', '.cmd', '.com');
/**
* Replaces default suffixes of executable.
*/
public function setSuffixes(array $suffixes)
{
$this->suffixes = $suffixes;
}
/**
* Adds new possible suffix to check for executable.
*
* @param string $suffix
*/
public function addSuffix($suffix)
{
$this->suffixes[] = $suffix;
}
/**
* Finds an executable by name.
*
* @param string $name The executable name (without the extension)
* @param string $default The default to return if no executable is found
* @param array $extraDirs Additional dirs to check into
*
* @return string The executable path or default value
*/
public function find($name, $default = null, array $extraDirs = array())
{
if (ini_get('open_basedir')) {
$searchPath = explode(PATH_SEPARATOR, ini_get('open_basedir'));
$dirs = array();
foreach ($searchPath as $path) {
// Silencing against https://bugs.php.net/69240
if (@is_dir($path)) {
$dirs[] = $path;
} else {
if (basename($path) == $name && @is_executable($path)) {
return $path;
}
}
}
} else {
$dirs = array_merge(
explode(PATH_SEPARATOR, getenv('PATH') ?: getenv('Path')),
$extraDirs
);
}
$suffixes = array('');
if ('\\' === DIRECTORY_SEPARATOR) {
$pathExt = getenv('PATHEXT');
$suffixes = array_merge($pathExt ? explode(PATH_SEPARATOR, $pathExt) : $this->suffixes, $suffixes);
}
foreach ($suffixes as $suffix) {
foreach ($dirs as $dir) {
if (@is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === DIRECTORY_SEPARATOR || @is_executable($file))) {
return $file;
}
}
}
return $default;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process;
use Symfony\Component\Process\Exception\RuntimeException;
/**
* Provides a way to continuously write to the input of a Process until the InputStream is closed.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class InputStream implements \IteratorAggregate
{
/** @var null|callable */
private $onEmpty = null;
private $input = array();
private $open = true;
/**
* Sets a callback that is called when the write buffer becomes empty.
*/
public function onEmpty(callable $onEmpty = null)
{
$this->onEmpty = $onEmpty;
}
/**
* Appends an input to the write buffer.
*
* @param resource|string|int|float|bool|\Traversable|null The input to append as scalar,
* stream resource or \Traversable
*/
public function write($input)
{
if (null === $input) {
return;
}
if ($this->isClosed()) {
throw new RuntimeException(sprintf('%s is closed', static::class));
}
$this->input[] = ProcessUtils::validateInput(__METHOD__, $input);
}
/**
* Closes the write buffer.
*/
public function close()
{
$this->open = false;
}
/**
* Tells whether the write buffer is closed or not.
*/
public function isClosed()
{
return !$this->open;
}
public function getIterator()
{
$this->open = true;
while ($this->open || $this->input) {
if (!$this->input) {
yield '';
continue;
}
$current = array_shift($this->input);
if ($current instanceof \Iterator) {
foreach ($current as $cur) {
yield $cur;
}
} else {
yield $current;
}
if (!$this->input && $this->open && null !== $onEmpty = $this->onEmpty) {
$this->write($onEmpty($this));
}
}
}
}
Copyright (c) 2004-2018 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process;
/**
* An executable finder specifically designed for the PHP executable.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class PhpExecutableFinder
{
private $executableFinder;
public function __construct()
{
$this->executableFinder = new ExecutableFinder();
}
/**
* Finds The PHP executable.
*
* @param bool $includeArgs Whether or not include command arguments
*
* @return string|false The PHP executable path or false if it cannot be found
*/
public function find($includeArgs = true)
{
if ($php = getenv('PHP_BINARY')) {
if (!is_executable($php)) {
return false;
}
return $php;
}
$args = $this->findArguments();
$args = $includeArgs && $args ? ' '.implode(' ', $args) : '';
// PHP_BINARY return the current sapi executable
if (PHP_BINARY && \in_array(PHP_SAPI, array('cli', 'cli-server', 'phpdbg'), true)) {
return PHP_BINARY.$args;
}
if ($php = getenv('PHP_PATH')) {
if (!@is_executable($php)) {
return false;
}
return $php;
}
if ($php = getenv('PHP_PEAR_PHP_BIN')) {
if (@is_executable($php)) {
return $php;
}
}
if (@is_executable($php = PHP_BINDIR.('\\' === DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
return $php;
}
$dirs = array(PHP_BINDIR);
if ('\\' === DIRECTORY_SEPARATOR) {
$dirs[] = 'C:\xampp\php\\';
}
return $this->executableFinder->find('php', false, $dirs);
}
/**
* Finds the PHP executable arguments.
*
* @return array The PHP executable arguments
*/
public function findArguments()
{
$arguments = array();
if ('phpdbg' === PHP_SAPI) {
$arguments[] = '-qrr';
}
return $arguments;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process;
use Symfony\Component\Process\Exception\RuntimeException;
/**
* PhpProcess runs a PHP script in an independent process.
*
* $p = new PhpProcess('<?php echo "foo"; ?>');
* $p->run();
* print $p->getOutput()."\n";
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PhpProcess extends Process
{
/**
* @param string $script The PHP script to run (as a string)
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to use the same environment as the current PHP process
* @param int $timeout The timeout in seconds
*/
public function __construct(string $script, string $cwd = null, array $env = null, int $timeout = 60)
{
$executableFinder = new PhpExecutableFinder();
if (false === $php = $executableFinder->find(false)) {
$php = null;
} else {
$php = array_merge(array($php), $executableFinder->findArguments());
}
if ('phpdbg' === PHP_SAPI) {
$file = tempnam(sys_get_temp_dir(), 'dbg');
file_put_contents($file, $script);
register_shutdown_function('unlink', $file);
$php[] = $file;
$script = null;
}
parent::__construct($php, $cwd, $env, $script, $timeout);
}
/**
* Sets the path to the PHP binary to use.
*/
public function setPhpBinary($php)
{
$this->setCommandLine($php);
}
/**
* {@inheritdoc}
*/
public function start(callable $callback = null, array $env = array())
{
if (null === $this->getCommandLine()) {
throw new RuntimeException('Unable to find the PHP executable.');
}
parent::start($callback, $env);
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Pipes;
use Symfony\Component\Process\Exception\InvalidArgumentException;
/**
* @author Romain Neutron <imprec@gmail.com>
*
* @internal
*/
abstract class AbstractPipes implements PipesInterface
{
public $pipes = array();
private $inputBuffer = '';
private $input;
private $blocked = true;
private $lastError;
/**
* @param resource|string|int|float|bool|\Iterator|null $input
*/
public function __construct($input)
{
if (is_resource($input) || $input instanceof \Iterator) {
$this->input = $input;
} elseif (is_string($input)) {
$this->inputBuffer = $input;
} else {
$this->inputBuffer = (string) $input;
}
}
/**
* {@inheritdoc}
*/
public function close()
{
foreach ($this->pipes as $pipe) {
fclose($pipe);
}
$this->pipes = array();
}
/**
* Returns true if a system call has been interrupted.
*
* @return bool
*/
protected function hasSystemCallBeenInterrupted()
{
$lastError = $this->lastError;
$this->lastError = null;
// stream_select returns false when the `select` system call is interrupted by an incoming signal
return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
}
/**
* Unblocks streams.
*/
protected function unblock()
{
if (!$this->blocked) {
return;
}
foreach ($this->pipes as $pipe) {
stream_set_blocking($pipe, 0);
}
if (is_resource($this->input)) {
stream_set_blocking($this->input, 0);
}
$this->blocked = false;
}
/**
* Writes input to stdin.
*
* @throws InvalidArgumentException When an input iterator yields a non supported value
*/
protected function write()
{
if (!isset($this->pipes[0])) {
return;
}
$input = $this->input;
if ($input instanceof \Iterator) {
if (!$input->valid()) {
$input = null;
} elseif (is_resource($input = $input->current())) {
stream_set_blocking($input, 0);
} elseif (!isset($this->inputBuffer[0])) {
if (!is_string($input)) {
if (!is_scalar($input)) {
throw new InvalidArgumentException(sprintf('%s yielded a value of type "%s", but only scalars and stream resources are supported', get_class($this->input), gettype($input)));
}
$input = (string) $input;
}
$this->inputBuffer = $input;
$this->input->next();
$input = null;
} else {
$input = null;
}
}
$r = $e = array();
$w = array($this->pipes[0]);
// let's have a look if something changed in streams
if (false === @stream_select($r, $w, $e, 0, 0)) {
return;
}
foreach ($w as $stdin) {
if (isset($this->inputBuffer[0])) {
$written = fwrite($stdin, $this->inputBuffer);
$this->inputBuffer = substr($this->inputBuffer, $written);
if (isset($this->inputBuffer[0])) {
return array($this->pipes[0]);
}
}
if ($input) {
for (;;) {
$data = fread($input, self::CHUNK_SIZE);
if (!isset($data[0])) {
break;
}
$written = fwrite($stdin, $data);
$data = substr($data, $written);
if (isset($data[0])) {
$this->inputBuffer = $data;
return array($this->pipes[0]);
}
}
if (feof($input)) {
if ($this->input instanceof \Iterator) {
$this->input->next();
} else {
$this->input = null;
}
}
}
}
// no input to read on resource, buffer is empty
if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
$this->input = null;
fclose($this->pipes[0]);
unset($this->pipes[0]);
} elseif (!$w) {
return array($this->pipes[0]);
}
}
/**
* @internal
*/
public function handleError($type, $msg)
{
$this->lastError = $msg;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Pipes;
/**
* PipesInterface manages descriptors and pipes for the use of proc_open.
*
* @author Romain Neutron <imprec@gmail.com>
*
* @internal
*/
interface PipesInterface
{
const CHUNK_SIZE = 16384;
/**
* Returns an array of descriptors for the use of proc_open.
*
* @return array
*/
public function getDescriptors();
/**
* Returns an array of filenames indexed by their related stream in case these pipes use temporary files.
*
* @return string[]
*/
public function getFiles();
/**
* Reads data in file handles and pipes.
*
* @param bool $blocking Whether to use blocking calls or not
* @param bool $close Whether to close pipes if they've reached EOF
*
* @return string[] An array of read data indexed by their fd
*/
public function readAndWrite($blocking, $close = false);
/**
* Returns if the current state has open file handles or pipes.
*
* @return bool
*/
public function areOpen();
/**
* Returns if pipes are able to read output.
*
* @return bool
*/
public function haveReadSupport();
/**
* Closes file handles and pipes.
*/
public function close();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Pipes;
use Symfony\Component\Process\Process;
/**
* UnixPipes implementation uses unix pipes as handles.
*
* @author Romain Neutron <imprec@gmail.com>
*
* @internal
*/
class UnixPipes extends AbstractPipes
{
private $ttyMode;
private $ptyMode;
private $haveReadSupport;
public function __construct(?bool $ttyMode, bool $ptyMode, $input, bool $haveReadSupport)
{
$this->ttyMode = $ttyMode;
$this->ptyMode = $ptyMode;
$this->haveReadSupport = $haveReadSupport;
parent::__construct($input);
}
public function __destruct()
{
$this->close();
}
/**
* {@inheritdoc}
*/
public function getDescriptors()
{
if (!$this->haveReadSupport) {
$nullstream = fopen('/dev/null', 'c');
return array(
array('pipe', 'r'),
$nullstream,
$nullstream,
);
}
if ($this->ttyMode) {
return array(
array('file', '/dev/tty', 'r'),
array('file', '/dev/tty', 'w'),
array('file', '/dev/tty', 'w'),
);
}
if ($this->ptyMode && Process::isPtySupported()) {
return array(
array('pty'),
array('pty'),
array('pty'),
);
}
return array(
array('pipe', 'r'),
array('pipe', 'w'), // stdout
array('pipe', 'w'), // stderr
);
}
/**
* {@inheritdoc}
*/
public function getFiles()
{
return array();
}
/**
* {@inheritdoc}
*/
public function readAndWrite($blocking, $close = false)
{
$this->unblock();
$w = $this->write();
$read = $e = array();
$r = $this->pipes;
unset($r[0]);
// let's have a look if something changed in streams
set_error_handler(array($this, 'handleError'));
if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
restore_error_handler();
// if a system call has been interrupted, forget about it, let's try again
// otherwise, an error occurred, let's reset pipes
if (!$this->hasSystemCallBeenInterrupted()) {
$this->pipes = array();
}
return $read;
}
restore_error_handler();
foreach ($r as $pipe) {
// prior PHP 5.4 the array passed to stream_select is modified and
// lose key association, we have to find back the key
$read[$type = array_search($pipe, $this->pipes, true)] = '';
do {
$data = fread($pipe, self::CHUNK_SIZE);
$read[$type] .= $data;
} while (isset($data[0]) && ($close || isset($data[self::CHUNK_SIZE - 1])));
if (!isset($read[$type][0])) {
unset($read[$type]);
}
if ($close && feof($pipe)) {
fclose($pipe);
unset($this->pipes[$type]);
}
}
return $read;
}
/**
* {@inheritdoc}
*/
public function haveReadSupport()
{
return $this->haveReadSupport;
}
/**
* {@inheritdoc}
*/
public function areOpen()
{
return (bool) $this->pipes;
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Pipes;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\RuntimeException;
/**
* WindowsPipes implementation uses temporary files as handles.
*
* @see https://bugs.php.net/bug.php?id=51800
* @see https://bugs.php.net/bug.php?id=65650
*
* @author Romain Neutron <imprec@gmail.com>
*
* @internal
*/
class WindowsPipes extends AbstractPipes
{
private $files = array();
private $fileHandles = array();
private $readBytes = array(
Process::STDOUT => 0,
Process::STDERR => 0,
);
private $haveReadSupport;
public function __construct($input, bool $haveReadSupport)
{
$this->haveReadSupport = $haveReadSupport;
if ($this->haveReadSupport) {
// Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
// Workaround for this problem is to use temporary files instead of pipes on Windows platform.
//
// @see https://bugs.php.net/bug.php?id=51800
$pipes = array(
Process::STDOUT => Process::OUT,
Process::STDERR => Process::ERR,
);
$tmpCheck = false;
$tmpDir = sys_get_temp_dir();
$lastError = 'unknown reason';
set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
for ($i = 0;; ++$i) {
foreach ($pipes as $pipe => $name) {
$file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
if (file_exists($file) && !unlink($file)) {
continue 2;
}
$h = fopen($file, 'xb');
if (!$h) {
$error = $lastError;
if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) {
continue;
}
restore_error_handler();
throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error));
}
if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) {
continue 2;
}
if (isset($this->files[$pipe])) {
unlink($this->files[$pipe]);
}
$this->files[$pipe] = $file;
}
break;
}
restore_error_handler();
}
parent::__construct($input);
}
public function __destruct()
{
$this->close();
$this->removeFiles();
}
/**
* {@inheritdoc}
*/
public function getDescriptors()
{
if (!$this->haveReadSupport) {
$nullstream = fopen('NUL', 'c');
return array(
array('pipe', 'r'),
$nullstream,
$nullstream,
);
}
// We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
// We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
// So we redirect output within the commandline and pass the nul device to the process
return array(
array('pipe', 'r'),
array('file', 'NUL', 'w'),
array('file', 'NUL', 'w'),
);
}
/**
* {@inheritdoc}
*/
public function getFiles()
{
return $this->files;
}
/**
* {@inheritdoc}
*/
public function readAndWrite($blocking, $close = false)
{
$this->unblock();
$w = $this->write();
$read = $r = $e = array();
if ($blocking) {
if ($w) {
@stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
} elseif ($this->fileHandles) {
usleep(Process::TIMEOUT_PRECISION * 1E6);
}
}
foreach ($this->fileHandles as $type => $fileHandle) {
$data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
if (isset($data[0])) {
$this->readBytes[$type] += strlen($data);
$read[$type] = $data;
}
if ($close) {
fclose($fileHandle);
unset($this->fileHandles[$type]);
}
}
return $read;
}
/**
* {@inheritdoc}
*/
public function haveReadSupport()
{
return $this->haveReadSupport;
}
/**
* {@inheritdoc}
*/
public function areOpen()
{
return $this->pipes && $this->fileHandles;
}
/**
* {@inheritdoc}
*/
public function close()
{
parent::close();
foreach ($this->fileHandles as $handle) {
fclose($handle);
}
$this->fileHandles = array();
}
/**
* Removes temporary files.
*/
private function removeFiles()
{
foreach ($this->files as $filename) {
if (file_exists($filename)) {
@unlink($filename);
}
}
$this->files = array();
}
}
This diff is collapsed.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process;
use Symfony\Component\Process\Exception\InvalidArgumentException;
/**
* ProcessUtils is a bunch of utility methods.
*
* This class contains static methods only and is not meant to be instantiated.
*
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class ProcessUtils
{
/**
* This class should not be instantiated.
*/
private function __construct()
{
}
/**
* Validates and normalizes a Process input.
*
* @param string $caller The name of method call that validates the input
* @param mixed $input The input to validate
*
* @return mixed The validated input
*
* @throws InvalidArgumentException In case the input is not valid
*/
public static function validateInput($caller, $input)
{
if (null !== $input) {
if (is_resource($input)) {
return $input;
}
if (is_string($input)) {
return $input;
}
if (is_scalar($input)) {
return (string) $input;
}
if ($input instanceof Process) {
return $input->getIterator($input::ITER_SKIP_ERR);
}
if ($input instanceof \Iterator) {
return $input;
}
if ($input instanceof \Traversable) {
return new \IteratorIterator($input);
}
throw new InvalidArgumentException(sprintf('%s only accepts strings, Traversable objects or stream resources.', $caller));
}
return $input;
}
}
Process Component
=================
The Process component executes commands in sub-processes.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/process.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\ExecutableFinder;
/**
* @author Chris Smith <chris@cs278.org>
*/
class ExecutableFinderTest extends TestCase
{
private $path;
protected function tearDown()
{
if ($this->path) {
// Restore path if it was changed.
putenv('PATH='.$this->path);
}
}
private function setPath($path)
{
$this->path = getenv('PATH');
putenv('PATH='.$path);
}
public function testFind()
{
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
$this->setPath(dirname(PHP_BINARY));
$finder = new ExecutableFinder();
$result = $finder->find($this->getPhpBinaryName());
$this->assertSamePath(PHP_BINARY, $result);
}
public function testFindWithDefault()
{
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
$expected = 'defaultValue';
$this->setPath('');
$finder = new ExecutableFinder();
$result = $finder->find('foo', $expected);
$this->assertEquals($expected, $result);
}
public function testFindWithExtraDirs()
{
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
$this->setPath('');
$extraDirs = array(dirname(PHP_BINARY));
$finder = new ExecutableFinder();
$result = $finder->find($this->getPhpBinaryName(), null, $extraDirs);
$this->assertSamePath(PHP_BINARY, $result);
}
public function testFindWithOpenBaseDir()
{
if ('\\' === DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Cannot run test on windows');
}
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
$this->iniSet('open_basedir', dirname(PHP_BINARY).PATH_SEPARATOR.'/');
$finder = new ExecutableFinder();
$result = $finder->find($this->getPhpBinaryName());
$this->assertSamePath(PHP_BINARY, $result);
}
public function testFindProcessInOpenBasedir()
{
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
if ('\\' === DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Cannot run test on windows');
}
$this->setPath('');
$this->iniSet('open_basedir', PHP_BINARY.PATH_SEPARATOR.'/');
$finder = new ExecutableFinder();
$result = $finder->find($this->getPhpBinaryName(), false);
$this->assertSamePath(PHP_BINARY, $result);
}
/**
* @requires PHP 5.4
*/
public function testFindBatchExecutableOnWindows()
{
if (ini_get('open_basedir')) {
$this->markTestSkipped('Cannot test when open_basedir is set');
}
if ('\\' !== DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Can be only tested on windows');
}
$target = tempnam(sys_get_temp_dir(), 'example-windows-executable');
touch($target);
touch($target.'.BAT');
$this->assertFalse(is_executable($target));
$this->setPath(sys_get_temp_dir());
$finder = new ExecutableFinder();
$result = $finder->find(basename($target), false);
unlink($target);
unlink($target.'.BAT');
$this->assertSamePath($target.'.BAT', $result);
}
private function assertSamePath($expected, $tested)
{
if ('\\' === DIRECTORY_SEPARATOR) {
$this->assertEquals(strtolower($expected), strtolower($tested));
} else {
$this->assertEquals($expected, $tested);
}
}
private function getPhpBinaryName()
{
return basename(PHP_BINARY, '\\' === DIRECTORY_SEPARATOR ? '.exe' : '');
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Runs a PHP script that can be stopped only with a SIGKILL (9) signal for 3 seconds.
*
* @args duration Run this script with a custom duration
*
* @example `php NonStopableProcess.php 42` will run the script for 42 seconds
*/
function handleSignal($signal)
{
switch ($signal) {
case SIGTERM:
$name = 'SIGTERM';
break;
case SIGINT:
$name = 'SIGINT';
break;
default:
$name = $signal.' (unknown)';
break;
}
echo "signal $name\n";
}
pcntl_signal(SIGTERM, 'handleSignal');
pcntl_signal(SIGINT, 'handleSignal');
echo 'received ';
$duration = isset($argv[1]) ? (int) $argv[1] : 3;
$start = microtime(true);
while ($duration > (microtime(true) - $start)) {
usleep(10000);
pcntl_signal_dispatch();
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\PhpExecutableFinder;
/**
* @author Robert Schönthal <seroscho@googlemail.com>
*/
class PhpExecutableFinderTest extends TestCase
{
/**
* tests find() with the constant PHP_BINARY.
*/
public function testFind()
{
$f = new PhpExecutableFinder();
$current = PHP_BINARY;
$args = 'phpdbg' === PHP_SAPI ? ' -qrr' : '';
$this->assertEquals($current.$args, $f->find(), '::find() returns the executable PHP');
$this->assertEquals($current, $f->find(false), '::find() returns the executable PHP');
}
/**
* tests find() with the env var PHP_PATH.
*/
public function testFindArguments()
{
$f = new PhpExecutableFinder();
if ('phpdbg' === PHP_SAPI) {
$this->assertEquals($f->findArguments(), array('-qrr'), '::findArguments() returns phpdbg arguments');
} else {
$this->assertEquals($f->findArguments(), array(), '::findArguments() returns no arguments');
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\PhpProcess;
class PhpProcessTest extends TestCase
{
public function testNonBlockingWorks()
{
$expected = 'hello world!';
$process = new PhpProcess(<<<PHP
<?php echo '$expected';
PHP
);
$process->start();
$process->wait();
$this->assertEquals($expected, $process->getOutput());
}
public function testCommandLine()
{
$process = new PhpProcess(<<<'PHP'
<?php echo phpversion().PHP_SAPI;
PHP
);
$commandLine = $process->getCommandLine();
$process->start();
$this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after start');
$process->wait();
$this->assertContains($commandLine, $process->getCommandLine(), '::getCommandLine() returns the command line of PHP after wait');
$this->assertSame(PHP_VERSION.PHP_SAPI, $process->getOutput());
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
define('ERR_SELECT_FAILED', 1);
define('ERR_TIMEOUT', 2);
define('ERR_READ_FAILED', 3);
define('ERR_WRITE_FAILED', 4);
$read = array(STDIN);
$write = array(STDOUT, STDERR);
stream_set_blocking(STDIN, 0);
stream_set_blocking(STDOUT, 0);
stream_set_blocking(STDERR, 0);
$out = $err = '';
while ($read || $write) {
$r = $read;
$w = $write;
$e = null;
$n = stream_select($r, $w, $e, 5);
if (false === $n) {
die(ERR_SELECT_FAILED);
} elseif ($n < 1) {
die(ERR_TIMEOUT);
}
if (in_array(STDOUT, $w) && strlen($out) > 0) {
$written = fwrite(STDOUT, (binary) $out, 32768);
if (false === $written) {
die(ERR_WRITE_FAILED);
}
$out = (binary) substr($out, $written);
}
if (null === $read && '' === $out) {
$write = array_diff($write, array(STDOUT));
}
if (in_array(STDERR, $w) && strlen($err) > 0) {
$written = fwrite(STDERR, (binary) $err, 32768);
if (false === $written) {
die(ERR_WRITE_FAILED);
}
$err = (binary) substr($err, $written);
}
if (null === $read && '' === $err) {
$write = array_diff($write, array(STDERR));
}
if ($r) {
$str = fread(STDIN, 32768);
if (false !== $str) {
$out .= $str;
$err .= $str;
}
if (false === $str || feof(STDIN)) {
$read = null;
if (!feof(STDIN)) {
die(ERR_READ_FAILED);
}
}
}
}
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Process\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Process\Exception\ProcessFailedException;
/**
* @author Sebastian Marek <proofek@gmail.com>
*/
class ProcessFailedExceptionTest extends TestCase
{
/**
* tests ProcessFailedException throws exception if the process was successful.
*/
public function testProcessFailedExceptionThrowsException()
{
$process = $this->getMockBuilder('Symfony\Component\Process\Process')->setMethods(array('isSuccessful'))->setConstructorArgs(array('php'))->getMock();
$process->expects($this->once())
->method('isSuccessful')
->will($this->returnValue(true));
if (method_exists($this, 'expectException')) {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Expected a failed process, but the given process was successful.');
} else {
$this->setExpectedException(\InvalidArgumentException::class, 'Expected a failed process, but the given process was successful.');
}
new ProcessFailedException($process);
}
/**
* tests ProcessFailedException uses information from process output
* to generate exception message.
*/
public function testProcessFailedExceptionPopulatesInformationFromProcessOutput()
{
$cmd = 'php';
$exitCode = 1;
$exitText = 'General error';
$output = 'Command output';
$errorOutput = 'FATAL: Unexpected error';
$workingDirectory = getcwd();
$process = $this->getMockBuilder('Symfony\Component\Process\Process')->setMethods(array('isSuccessful', 'getOutput', 'getErrorOutput', 'getExitCode', 'getExitCodeText', 'isOutputDisabled', 'getWorkingDirectory'))->setConstructorArgs(array($cmd))->getMock();
$process->expects($this->once())
->method('isSuccessful')
->will($this->returnValue(false));
$process->expects($this->once())
->method('getOutput')
->will($this->returnValue($output));
$process->expects($this->once())
->method('getErrorOutput')
->will($this->returnValue($errorOutput));
$process->expects($this->once())
->method('getExitCode')
->will($this->returnValue($exitCode));
$process->expects($this->once())
->method('getExitCodeText')
->will($this->returnValue($exitText));
$process->expects($this->once())
->method('isOutputDisabled')
->will($this->returnValue(false));
$process->expects($this->once())
->method('getWorkingDirectory')
->will($this->returnValue($workingDirectory));
$exception = new ProcessFailedException($process);
$this->assertEquals(
"The command \"$cmd\" failed.\n\nExit Code: $exitCode($exitText)\n\nWorking directory: {$workingDirectory}\n\nOutput:\n================\n{$output}\n\nError Output:\n================\n{$errorOutput}",
$exception->getMessage()
);
}
/**
* Tests that ProcessFailedException does not extract information from
* process output if it was previously disabled.
*/
public function testDisabledOutputInFailedExceptionDoesNotPopulateOutput()
{
$cmd = 'php';
$exitCode = 1;
$exitText = 'General error';
$workingDirectory = getcwd();
$process = $this->getMockBuilder('Symfony\Component\Process\Process')->setMethods(array('isSuccessful', 'isOutputDisabled', 'getExitCode', 'getExitCodeText', 'getOutput', 'getErrorOutput', 'getWorkingDirectory'))->setConstructorArgs(array($cmd))->getMock();
$process->expects($this->once())
->method('isSuccessful')
->will($this->returnValue(false));
$process->expects($this->never())
->method('getOutput');
$process->expects($this->never())
->method('getErrorOutput');
$process->expects($this->once())
->method('getExitCode')
->will($this->returnValue($exitCode));
$process->expects($this->once())
->method('getExitCodeText')
->will($this->returnValue($exitText));
$process->expects($this->once())
->method('isOutputDisabled')
->will($this->returnValue(true));
$process->expects($this->once())
->method('getWorkingDirectory')
->will($this->returnValue($workingDirectory));
$exception = new ProcessFailedException($process);
$this->assertEquals(
"The command \"$cmd\" failed.\n\nExit Code: $exitCode($exitText)\n\nWorking directory: {$workingDirectory}",
$exception->getMessage()
);
}
}
This diff is collapsed.
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
pcntl_signal(SIGUSR1, function () { echo 'SIGUSR1'; exit; });
echo 'Caught ';
$n = 0;
while ($n++ < 400) {
usleep(10000);
pcntl_signal_dispatch();
}
{
"name": "symfony/process",
"type": "library",
"description": "Symfony Process Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": "^7.1.3"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Process\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "4.1-dev"
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Process Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<directory>./Tests</directory>
<directory>./vendor</directory>
</exclude>
</whitelist>
</filter>
</phpunit>
Yii2 Queue Extension Change Log
===============================
2.1.0 May 24, 2018
------------------
- Bug #210: Worker option to define php bin path to run child process (zhuravljov)
- Enh: Worker loop event (zhuravljov)
- Bug #207: Console params validation (zhuravljov)
- Bug #224: Invalid identifier "DELAY" (lar-dragon)
- Enh #192: AWS SQS implementation (elitemaks, manoj-girnar)
- Bug #126: Handles a fatal error of the job execution in isolate mode (zhuravljov)
2.0.2 December 26, 2017
-----------------------
- Bug #92: Resolve issue in debug panel (farmani-eigital)
- Bug #99: Retry connecting after connection has timed out for redis driver (cebe)
- Bug #180: Fixed info command of file driver (victorruan)
- Enh #158: Add Amqp Interop driver (makasim)
- Enh #185: Loop object instead of Signal helper (zhuravljov)
- Enh #188: Configurable verbose mode (zhuravljov)
- Enh: Start and stop events of a worker (zhuravljov)
2.0.1 November 13, 2017
-----------------------
- Bug #98: Fixed timeout error handler (zhuravljov)
- Bug #112: Queue command inside module (tsingsun)
- Bug #118: Synchronized moving of delayed and reserved jobs to waiting list (zhuravljov)
- Bug #155: Slave DB breaks listener (zhuravljov)
- Enh #97: `Queue::status` is public method (zhuravljov)
- Enh #116: Add Chinese Guide (kids-return)
- Enh #122: Rename `Job` to `JobInterface` (zhuravljov)
- Enh #137: All throwable errors caused by jobs are now caught (brandonkelly)
- Enh #141: Clear and remove commands for File, DB, Beanstalk and Redis drivers (zhuravljov)
- Enh #147: Igbinary job serializer (xutl)
- Enh #148: Allow to change vhost setting for RabbitMQ (ischenko)
- Enh #151: Compatibility with Yii 2.0.13 and PHP 7.2 (zhuravljov)
- Enh #160: Benchmark of job wait time (zhuravljov)
- Enh: Rename `cli\Verbose` behavior to `cli\VerboseBehavior` (zhuravljov)
- Enh: Rename `serializers\Serializer` interface to `serializers\SerializerInterface` (zhuravljov)
- Enh: Added `Signal::setExitFlag()` to stop `Queue::run()` loop manually (silverfire)
2.0.0 July 15, 2017
-------------------
- Enh: The package is moved to yiisoft/yii2-queue (zhuravljov)
1.1.0 July 12, 2017
-------------------
- Enh #50 Documentation about worker starting control (zhuravljov)
- Enh #70: Durability for rabbitmq queues (mkubenka)
- Enh: Detailed error about job type in message handling (zhuravljov)
- Enh #60: Enhanced event handling (zhuravljov)
- Enh: Job priority for DB driver (zhuravljov)
- Enh: File mode options of file driver (zhuravljov)
- Enh #47: Redis queue listen timeout (zhuravljov)
- Enh #23: Retryable jobs (zhuravljov)
1.0.1 June 7, 2017
------------------
- Enh #58: Deleting failed jobs from queue (zhuravljov)
- Enh #55: Job priority (zhuravljov)
1.0.0 May 4, 2017
-----------------
- Enh: Improvements of log behavior (zhuravljov)
- Enh: File driver stat info (zhuravljov)
- Enh: Beanstalk stat info (zhuravljov)
- Enh: Colorized driver info actions (zhuravljov)
- Enh: Colorized verbose mode (zhuravljov)
- Enh: Improvements of debug panel (zhuravljov)
- Enh: Queue job message statuses (zhuravljov)
- Enh: Gii job generator (zhuravljov)
- Enh: Enhanced gearman driver (zhuravljov)
- Enh: Queue message identifiers (zhuravljov)
- Enh: File queue (zhuravljov)
0.12.2 April 29, 2017
---------------------
- Enh #10: Separate option that turn off isolate mode of job execute (zhuravljov)
0.12.1 April 20, 2017
---------------------
- Bug #37: Fixed opening of a child process (zhuravljov)
- Enh: Ability to push a closure (zhuravljov)
- Enh: Before push event (zhuravljov)
0.12.0 April 14, 2017
---------------------
- Enh #18: Executes a job in a child process (zhuravljov)
- Bug #25: Enabled output buffer breaks output streams (luke-)
- Enh: After push event (zhuravljov)
0.11.0 April 2, 2017
--------------------
- Enh #21: Delayed jobs for redis queue (zhuravljov)
- Enh: Info action for db and redis queue command (zhuravljov)
0.10.1 March 29, 2017
---------------------
- Bug: Fixed db driver for pgsql (zhuravljov)
- Bug #16: Timeout of  queue reading lock for db driver (zhuravljov)
- Enh: Minor code style enhancements (SilverFire)
0.10.0 March 22, 2017
---------------------
- Enh #14: Json job serializer (zhuravljov)
- Enh: Delayed running of a job (zhuravljov)
0.9.1 March 6, 2017
-------------------
- Bug #13: Fixed reading of DB queue (zhuravljov)
0.9.0 March 6, 2017
-------------------
- Enh: Signal handlers (zhuravljov)
- Enh: Add exchange for AMQP driver (airani)
- Enh: Beanstalk driver (zhuravljov)
- Enh: Added English docs (samdark)
Copyright © 2008 by Yii Software LLC (http://www.yiisoft.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of Yii Software LLC nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
<p align="center">
<a href="https://github.com/yiisoft" target="_blank">
<img src="https://avatars0.githubusercontent.com/u/993323" height="100px">
</a>
<h1 align="center">Yii2 Queue Extension</h1>
<br>
</p>
An extension for running tasks asynchronously via queues.
It supports queues based on **DB**, **Redis**, **RabbitMQ**, **AMQP**, **Beanstalk** and **Gearman**.
Documentation is at [docs/guide/README.md](docs/guide/README.md).
[![Latest Stable Version](https://poser.pugx.org/yiisoft/yii2-queue/v/stable.svg)](https://packagist.org/packages/yiisoft/yii2-queue)
[![Total Downloads](https://poser.pugx.org/yiisoft/yii2-queue/downloads.svg)](https://packagist.org/packages/yiisoft/yii2-queue)
[![Build Status](https://travis-ci.org/yiisoft/yii2-queue.svg?branch=master)](https://travis-ci.org/yiisoft/yii2-queue)
Installation
------------
The preferred way to install this extension is through [composer](http://getcomposer.org/download/).
Either run
```
php composer.phar require --prefer-dist yiisoft/yii2-queue
```
or add
```
"yiisoft/yii2-queue": "~2.0.0"
```
to the require section of your `composer.json` file.
Basic Usage
-----------
Each task which is sent to queue should be defined as a separate class.
For example, if you need to download and save a file the class may look like the following:
```php
class DownloadJob extends BaseObject implements \yii\queue\JobInterface
{
public $url;
public $file;
public function execute($queue)
{
file_put_contents($this->file, file_get_contents($this->url));
}
}
```
Here's how to send a task into the queue:
```php
Yii::$app->queue->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
```
To push a job into the queue that should run after 5 minutes:
```php
Yii::$app->queue->delay(5 * 60)->push(new DownloadJob([
'url' => 'http://example.com/image.jpg',
'file' => '/tmp/image.jpg',
]));
```
The exact way a task is executed depends on the used driver. Most drivers can be run using
console commands, which the component automatically registers in your application.
This command obtains and executes tasks in a loop until the queue is empty:
```sh
yii queue/run
```
This command launches a daemon which infinitely queries the queue:
```sh
yii queue/listen
```
See the documentation for more details about driver specific console commands and their options.
The component also has the ability to track the status of a job which was pushed into queue.
```php
// Push a job into the queue and get a message ID.
$id = Yii::$app->queue->push(new SomeJob());
// Check whether the job is waiting for execution.
Yii::$app->queue->isWaiting($id);
// Check whether a worker got the job from the queue and executes it.
Yii::$app->queue->isReserved($id);
// Check whether a worker has executed the job.
Yii::$app->queue->isDone($id);
```
For more details see [the guide](docs/guide/README.md).
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment