first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
{
"name": "wpdesk\/abstract-shipping",
"description": "Abstract Shipping",
"license": "MIT",
"keywords": [
"wordpress",
"woocommerce",
"shipping"
],
"homepage": "https:\/\/gitlab.com\/wpdesk\/abstract-shipping",
"authors": [
{
"name": "grola",
"email": "grola@wpdesk.net"
}
],
"require": {
"php": ">=5.6",
"ext-json": "*",
"psr\/log": "^1.1"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"phpcompatibility\/php-compatibility": "^9.1"
},
"autoload": {
"psr-4": {
"VendorDHL\\WPDesk\\AbstractShipping\\": "src\/AbstractShipping"
}
},
"autoload-dev": {
"classmap": [
"tests\/unit"
]
},
"extra": {
"text-domain": "abstract-shipping",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po",
"en_AU": "en_AU.po",
"en_CA": "en_CA.po",
"en_GB": "en_GB.po",
"de_DE": "de_DE.po"
}
},
"scripts": {
"phpcs": "phpcs",
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
}
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Simple DTO: SingleCollectionPoint class.
*
* @package WPDesk\AbstractShipping\CollectionPoint
*/
namespace VendorDHL\WPDesk\AbstractShipping\CollectionPoints;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Address;
/**
* Define Single Collection Point.
*/
final class CollectionPoint
{
/**
* Collection point ID.
*
* @var string
*/
public $collection_point_id;
/**
* Collection point name.
*
* @var string
*/
public $collection_point_name;
/**
* Address.
*
* @var Address
*/
public $collection_point_address;
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Capability: CollectionPointsProvider class
*
* @package WPDesk\AbstractShipping\CollectionPointCapability
*/
namespace VendorDHL\WPDesk\AbstractShipping\CollectionPointCapability;
use VendorDHL\WPDesk\AbstractShipping\CollectionPoints\CollectionPoint;
use VendorDHL\WPDesk\AbstractShipping\Exception\CollectionPointNotFoundException;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Address;
/**
* Interface for classes that provides collections points.
*/
interface CollectionPointsProvider
{
/**
* Get nearest collection points to given address.
*
* @param Address $address .
*
* @return CollectionPoint[]
* @throws CollectionPointNotFoundException
*/
public function get_nearest_collection_points(\VendorDHL\WPDesk\AbstractShipping\Shipment\Address $address);
/**
* Get single nearest collection point to given address.
*
* @param Address $address .
*
* @return CollectionPoint
* @throws CollectionPointNotFoundException
*/
public function get_single_nearest_collection_point(\VendorDHL\WPDesk\AbstractShipping\Shipment\Address $address);
/**
* Get get collection point by given id.
*
* @param string $collection_point_id .
* @param string $country_code .
*
* @return CollectionPoint
* @throws CollectionPointNotFoundException .
*/
public function get_point_by_id($collection_point_id, $country_code);
}

View File

@@ -0,0 +1,12 @@
<?php
/**
* Exception thrown when connection checker fails.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
class ApiConnectionCheckerException extends \RuntimeException
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Custom Exception for CollectionPointNotFoundException.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Exception thrown when collection point not found.
*
* @package WPDesk\AbstractShipping\Exception
*/
class CollectionPointNotFoundException extends \RuntimeException
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Custom Exception for InvalidSettingsException.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Exception thrown by service in case the settings do not pass the validation.
*
* @package WPDesk\AbstractShipping\Exception
*/
class InvalidSettingsException extends \RuntimeException implements \VendorDHL\WPDesk\AbstractShipping\Exception\ShippingException
{
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Custom Exception for Rates.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Exception thrown when rates is empty.
*
* @package WPDesk\AbstractShipping\Exception
*/
class RateException extends \RuntimeException implements \VendorDHL\WPDesk\AbstractShipping\Exception\ShippingException
{
/**
* Context.
*
* @var array
*/
private $context;
/**
* RateException constructor.
*
* @param string $message Message.
* @param array $context Context.
* @param int $code Code.
* @param null $previous Previous.
*/
public function __construct($message = '', $context = [], $code = 0, $previous = null)
{
parent::__construct($message, $code, $previous);
$this->context = $context;
}
/**
* Get context.
*
* @return array
*/
public function get_context()
{
return $this->context;
}
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Custom Exception when settings field not exists.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Exception thrown when settings field not exists.
*
* @package WPDesk\AbstractShipping\Exception
*/
class SettingsFieldNotExistsException extends \Exception
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Shipping exception interface.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Shipping exception interface.
*
* @package WPDesk\AbstractShipping\Exception
*/
interface ShippingException
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Custom Exception for unit conversion.
*
* @package WPDesk\AbstractShipping\Exception
*/
namespace VendorDHL\WPDesk\AbstractShipping\Exception;
/**
* Exception thrown when can't convert to other unit.
*
* @package WPDesk\AbstractShipping\Exception
*/
class UnitConversionException extends \Exception
{
}

View File

@@ -0,0 +1,29 @@
<?php
/**
* Simple DTO: Money class.
*
* @package WPDesk\AbstractShipping
*/
namespace VendorDHL\WPDesk\AbstractShipping\Rate;
/**
* Class for prepare data returned by plugin.
*
* @package WPDesk\AbstractShipping
*/
final class Money
{
/**
* Value in string field but usually is INT
*
* @var string|float
*/
public $amount;
/**
* Currency.
*
* @var string In ISO 4217
*/
public $currency;
}

View File

@@ -0,0 +1,23 @@
<?php
/**
* Simple DTO: ShipmentRating interface.
*
* @package WPDesk\AbstractShipping\Rate
*/
namespace VendorDHL\WPDesk\AbstractShipping\Rate;
/**
* Interface for classes that store shipment prices. It will be returned by CanRate::get_rates.
*
* @package WPDesk\AbstractShipping\Rate
*/
interface ShipmentRating
{
/**
* Get ratings.
*
* @return SingleRate[]
*/
public function get_ratings();
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* Simple DTO: ShipmentRatingImplementation class.
*
* @package WPDesk\AbstractShipping
*/
namespace VendorDHL\WPDesk\AbstractShipping\Rate;
/**
* Part of AbstractShipping package which provides uniform interface between WC and Shipment API.
*
* @package WPDesk\AbstractShipping
*/
class ShipmentRatingImplementation implements \VendorDHL\WPDesk\AbstractShipping\Rate\ShipmentRating
{
/**
* Rates.
*
* @var SingleRate[]
*/
private $rates;
/**
* ShipmentRatingImplementation constructor.
*
* @param array $rates SingleRate[].
*/
public function __construct(array $rates)
{
$this->rates = $rates;
}
/**
* Get ratings.
*
* @return SingleRate[]
*/
public function get_ratings()
{
return $this->rates;
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Simple DTO: SingleRate class.
*
* @package WPDesk\AbstractShipping\Rate
*/
namespace VendorDHL\WPDesk\AbstractShipping\Rate;
/**
* Define Single Rate.
*
* @package WPDesk\AbstractShipping\Rate
*/
final class SingleRate
{
/**
* Service type.
*
* @var string
*/
public $service_type;
/**
* Service name.
*
* @var string
*/
public $service_name;
/**
* Total charge.
*
* @var Money
*/
public $total_charge;
/**
* Is collection point rate?
*
* @var bool
*/
public $is_collection_point_rate = \false;
/**
* Estimated delivery date. Should be here if service implements CanReturnDeliveryDate interface.
*
* @var \DateTimeInterface|null
*/
public $delivery_date;
/**
* Estimated number business days in transit. Should be here if service implements CanReturnDeliveryDate interface.
*
* @var int|null
*/
public $business_days_in_transit;
}

View File

@@ -0,0 +1,68 @@
<?php
/**
* Class BlackoutLeadDays
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings;
/**
* Can calculate date according to blackout days.
*/
class BlackoutLeadDays
{
/**
* @var array
*/
private $blackout_days;
/**
* @var int
*/
private $lead_days;
/**
* BlackoutLeadDays constructor.
*
* @param array $blackout_days .
* @param int $lead_days .
*/
public function __construct(array $blackout_days, $lead_days)
{
$this->blackout_days = $blackout_days;
$this->lead_days = $lead_days;
}
/**
* @param \DateTime $calculated_date .
*
* @return \DateTime
*/
public function calculate_date(\DateTime $calculated_date)
{
$lead_days = $this->lead_days;
$one_day_date_interval = new \DateInterval('P1D');
$calculated_date = $this->increase_date_while_in_blackout_days($calculated_date, $one_day_date_interval);
while ($lead_days) {
$calculated_date = $calculated_date->add($one_day_date_interval);
$calculated_date->setTime(0, 0);
$calculated_date = $this->increase_date_while_in_blackout_days($calculated_date, $one_day_date_interval);
$lead_days--;
}
return $calculated_date;
}
/**
* @param \DateTime $calculated_date .
* @param \DateInterval $one_day_date_interval .
*
* @return \DateTime
*/
private function increase_date_while_in_blackout_days(\DateTime $calculated_date, \DateInterval $one_day_date_interval)
{
$calculated_date_week_day = $calculated_date->format('N');
while (\in_array($calculated_date_week_day, $this->blackout_days, \true)) {
$calculated_date->add($one_day_date_interval);
$calculated_date->setTime(0, 0);
$calculated_date_week_day = $calculated_date->format('N');
}
return $calculated_date;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Settings container: SettingsDefinitionModifierAfter.
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier;
use VendorDHL\WPDesk\AbstractShipping\Exception\SettingsFieldNotExistsException;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues;
/**
* Can decorate settings by adding settings field after given field.
*/
class SettingsDefinitionModifierAfter extends \VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition
{
/**
* Decorated settings definition.
*
* @var SettingsDefinition
*/
private $decorated_settings_definition;
/**
* Field id.
*
* @var string
*/
private $field_id_after;
/**
* New field id.
*
* @var string
*/
private $new_field_id;
/**
* New field.
*
* @var array
*/
private $new_field;
/**
* SettingsDefinitionModifierBefore constructor.
*
* @param SettingsDefinition $decorated_settings_definition Decorated settings definition,
* @param string $field_id_after Field id before which should be settings added.
* @param string $new_field_id New field id.
* @param array $new_field New field.
*/
public function __construct(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition $decorated_settings_definition, $field_id_after, $new_field_id, array $new_field)
{
$this->decorated_settings_definition = $decorated_settings_definition;
$this->field_id_after = $field_id_after;
$this->new_field_id = $new_field_id;
$this->new_field = $new_field;
}
/**
* Returns modified form fields.
*
* @param array $form_fields
*
* @return array
*
* @throws SettingsFieldNotExistsException
*/
public function get_form_fields()
{
$form_fields = $this->decorated_settings_definition->get_form_fields();
if (isset($form_fields[$this->field_id_after])) {
$modified_form_fields = [];
foreach ($form_fields as $field_id => $field) {
$modified_form_fields[$field_id] = $field;
if ($field_id === $this->field_id_after) {
$modified_form_fields[$this->new_field_id] = $this->new_field;
}
}
return $modified_form_fields;
}
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\SettingsFieldNotExistsException(\sprintf('Field %1$s not found in settings!', $this->field_id_after));
}
/**
* Validate settings.
*
* @param SettingsValues $settings Settings values.
*
* @return bool
*/
public function validate_settings(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings)
{
return $this->decorated_settings_definition->validate_settings($settings);
}
}

View File

@@ -0,0 +1,92 @@
<?php
/**
* Settings container: SettingsDefinitionModifierBefore.
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier;
use VendorDHL\WPDesk\AbstractShipping\Exception\SettingsFieldNotExistsException;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues;
/**
* Can modify settings by adding settings field before given field.
*/
class SettingsDefinitionModifierBefore extends \VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition
{
/**
* Decorated settings definition.
*
* @var SettingsDefinition
*/
private $decorated_settings_definition;
/**
* Field id.
*
* @var string
*/
private $field_id_before;
/**
* New field id.
*
* @var string
*/
private $new_field_id;
/**
* New field.
*
* @var array
*/
private $new_field;
/**
* SettingsDefinitionModifierBefore constructor.
*
* @param SettingsDefinition $decorated_settings_definition Decorated settings definition,
* @param string $field_id_before Field id before which should be settings added.
* @param string $new_field_id New field id.
* @param array $new_field New field.
*/
public function __construct(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition $decorated_settings_definition, $field_id_before, $new_field_id, array $new_field)
{
$this->decorated_settings_definition = $decorated_settings_definition;
$this->field_id_before = $field_id_before;
$this->new_field_id = $new_field_id;
$this->new_field = $new_field;
}
/**
* Returns modified form fields.
*
* @param array $form_fields
*
* @return array
*
* @throws SettingsFieldNotExistsException
*/
public function get_form_fields()
{
$form_fields = $this->decorated_settings_definition->get_form_fields();
if (isset($form_fields[$this->field_id_before])) {
$modified_form_fields = [];
foreach ($form_fields as $field_id => $field) {
if ($field_id === $this->field_id_before) {
$modified_form_fields[$this->new_field_id] = $this->new_field;
}
$modified_form_fields[$field_id] = $field;
}
return $modified_form_fields;
}
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\SettingsFieldNotExistsException(\sprintf('Field %1$s not found in settings!', $this->field_id_before));
}
/**
* Validate settings.
*
* @param SettingsValues $settings Settings values.
*
* @return bool
*/
public function validate_settings(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings)
{
return $this->decorated_settings_definition->validate_settings($settings);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Class AbstractDecoratorFactory
* @package WPDesk\AbstractShipping\Settings\SettingsDecorators
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDecorators;
use VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier\SettingsDefinitionModifierAfter;
use VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier\SettingsDefinitionModifierBefore;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition;
/**
* Abstract factory.
*/
abstract class AbstractDecoratorFactory
{
/**
* @param SettingsDefinition $settings_definition .
* @param string $related_field_id .
* @param bool $before .
* @param string $field_id .
*
* @return SettingsDefinition
*/
public function create_decorator(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition $settings_definition, $related_field_id, $before = \true, $field_id = null)
{
$decorator_class = $this->get_settings_definition_modifier_class($before);
return new $decorator_class($settings_definition, $related_field_id, empty($field_id) ? $this->get_field_id() : $field_id, $this->get_field_settings());
}
/**
* @return string
*/
protected abstract function get_field_settings();
/**
* @return array
*/
public abstract function get_field_id();
/**
* @param bool $before .
*
* @return string
*/
protected function get_settings_definition_modifier_class($before = \true)
{
return $before ? \VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier\SettingsDefinitionModifierBefore::class : \VendorDHL\WPDesk\AbstractShipping\Settings\DefinitionModifier\SettingsDefinitionModifierAfter::class;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* Class BlackoutLeadDaysSettingsDefinitionDecoratorFactory
*
* @package WPDesk\AbstractShipping\Settings\SettingsDecorators
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDecorators;
/**
* Can create Blackout Lead Days settings decorator.
*/
class BlackoutLeadDaysSettingsDefinitionDecoratorFactory extends \VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDecorators\AbstractDecoratorFactory
{
const OPTION_ID = 'blackout_lead_days';
/**
* @return string
*/
public function get_field_id()
{
return self::OPTION_ID;
}
/**
* @return array
*/
protected function get_field_settings()
{
return array('title' => \__('Blackout Lead Days', 'woocommerce-dhl'), 'type' => 'multiselect', 'description' => \__('Blackout Lead Days are used to define days of the week when shop is not processing orders.', 'woocommerce-dhl'), 'options' => array('1' => \__('Monday', 'woocommerce-dhl'), '2' => \__('Tuesday', 'woocommerce-dhl'), '3' => \__('Wednesday', 'woocommerce-dhl'), '4' => \__('Thursday', 'woocommerce-dhl'), '5' => \__('Friday', 'woocommerce-dhl'), '6' => \__('Saturday', 'woocommerce-dhl'), '7' => \__('Sunday', 'woocommerce-dhl')), 'custom_attributes' => array('size' => 7), 'class' => 'wc-enhanced-select', 'desc_tip' => \true, 'default' => '');
}
}

View File

@@ -0,0 +1,31 @@
<?php
/**
* Settings container: SettingsDefinition.
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings;
/**
* Abstract class for create default settings data.
*
* @package WPDesk\AbstractShipping\Settings
*/
abstract class SettingsDefinition
{
/**
* Validate settings.
*
* @param SettingsValues $settings Settings values.
*
* @return bool
*/
public abstract function validate_settings(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings);
/**
* Get settings.
*
* @return array
*/
public abstract function get_form_fields();
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Settings container: SettingsDefinition.
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings;
/**
* Interface for SettingsValuesAsArray class.
*
* @package WPDesk\AbstractShipping\Settings
*/
interface SettingsValues
{
/**
* Get value.
*
* @param string $name Setting name.
* @param string|null $default Default value.
*
* @return mixed
*/
public function get_value($name, $default = null);
/**
* Has value.
*
* @param string $name Setting name.
*
* @return bool
*/
public function has_value($name);
}

View File

@@ -0,0 +1,64 @@
<?php
/**
* Settings container: SettingsValuesAsArray.
*
* @package WPDesk\AbstractShipping\Settings
*/
namespace VendorDHL\WPDesk\AbstractShipping\Settings;
/**
* Container class for settings data.
*
* @package WPDesk\AbstractShipping\Settings
*/
class SettingsValuesAsArray implements \VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues
{
/**
* Values.
*
* @var array
*/
private $values;
/**
* SettingsValuesAsArray constructor.
*
* @param array $values Array values.
*/
public function __construct(array $values)
{
$this->values = $values;
}
/**
* Get value.
*
* @param string $name Setting name.
* @param string|null $default Default value if no value found.
*
* @return mixed
*/
public function get_value($name, $default = null)
{
return $this->has_value($name) ? $this->values[$name] : $default;
}
/**
* Has value.
*
* @param string $name Setting name.
*
* @return bool
*/
public function has_value($name)
{
return isset($this->values[$name]);
}
/**
* Get settings md5 hash.
*
* @return string
*/
public function get_settings_md5_hash()
{
return \md5(\json_encode($this->values));
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Simple DTO: Address class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores the customer's address data.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Address
{
/**
* Adress line 2.
*
* @var string
*/
public $address_line1;
/**
* Adress line 2.
*
* @var string
*/
public $address_line2;
/**
* Postal code.
*
* @var string
*/
public $postal_code;
/**
* City.
*
* @var string
*/
public $city;
/**
* State code.
*
* @var string
*/
public $state_code;
/**
* Country code.
*
* @var string
*/
public $country_code;
/**
* Street lines
*
* @var array
*/
public $street_lines = [];
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Simple DTO: Client class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores the client data
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Client
{
/**
* Address.
*
* @var Address
*/
public $address;
/**
* E-mail.
*
* @var string
*/
public $email;
/**
* Phone number.
*
* @var string|null
*/
public $phone_number;
/**
* Name.
*
* @var string
*/
public $name;
/**
* Company name.
*
* @var string|null
*/
public $company_name;
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Simple DTO: Dimensions class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores the package dimensions.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Dimensions
{
const DIMENSION_UNIT_MM = 'MM';
const DIMENSION_UNIT_CM = 'CM';
const DIMENSION_UNIT_M = 'M';
const DIMENSION_UNIT_IN = 'IN';
/**
* Height.
*
* @var int
*/
public $height;
/**
* Width.
*
* @var int
*/
public $width;
/**
* Length.
*
* @var int
*/
public $length;
/**
* Dimension unit.
*
* @var string
*/
public $dimensions_unit;
}

View File

@@ -0,0 +1,42 @@
<?php
/**
* Simple DTO: Item class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
use VendorDHL\WPDesk\AbstractShipping\Rate\Money;
/**
* Class that stores items for package.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Item
{
/**
* Item name.
*
* @var string
*/
public $name;
/**
* Item weight.
*
* @var Weight
*/
public $weight;
/**
* Item dimensions.
*
* @var Dimensions
*/
public $dimensions;
/**
* Declared value of item ie. for Insurance.
*
* @var Money|null
*/
public $declared_value;
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Simple DTO: Package class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores packages data for shipment.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Package
{
/** Items packed in this package.
*
* @var Item[]
*/
public $items;
/**
* Item weight. Can be null if not packed.
*
* @var Weight|null
*/
public $weight;
/**
* Item dimensions. Can be null if not packed.
*
* @var Dimensions|null
*/
public $dimensions;
/**
* Packages can be a special packages with type ie. CUBE_BOX . If not set then shipment should use custom type.
*
* @var string|null
*/
public $package_type;
/**
* Packages can have a descriptive name.
*
* @var string|null
*/
public $description;
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Simple DTO: Shipment class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores shipment data.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Shipment
{
/**
* Ship from
*
* @var Client
*/
public $ship_from;
/**
* Ship to.
*
* @var Client
*/
public $ship_to;
/**
* Packages.
*
* @var Package[]
*/
public $packages;
/**
* Should use insurance if possible. Declared item values will be in Item::declared_value.
*
* @var bool
*/
public $insurance = \false;
/**
* If packed then Package::Weight, Package::Dimension should be not null.
* Package:package_type and Package:description can still be null.
*
* It means that packer tried to pack items into packages and size/weight of these packages is more important for rating
* than the size of items.
*
* @var bool
*/
public $packed = \false;
}

View File

@@ -0,0 +1,34 @@
<?php
/**
* Simple DTO: Shipment class.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\Shipment;
/**
* Class that stores weight data for Item.
*
* @package WPDesk\AbstractShipping\Shipment
*/
final class Weight
{
const WEIGHT_UNIT_KG = 'KG';
const WEIGHT_UNIT_G = 'G';
const WEIGHT_UNIT_LB = 'LB';
const WEIGHT_UNIT_LBS = 'LBS';
const WEIGHT_UNIT_OZ = 'OZ';
/**
* Weight KGS by default
*
* @var float
*/
public $weight;
/**
* Weight unit.
*
* @var string
*/
public $weight_unit;
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Shipping service abstract: ShippingService class.
*
* @package WPDesk\AbstractShipping
*/
namespace VendorDHL\WPDesk\AbstractShipping;
use VendorDHL\Psr\Log\LoggerAwareInterface;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition;
/**
* Basic abstract class for shipping classes.
*
* @package WPDesk\AbstractShipping
*/
abstract class ShippingService implements \VendorDHL\Psr\Log\LoggerAwareInterface
{
/**
* Get unique ID.
*
* @return string
*/
public abstract function get_unique_id();
/**
* Get name.
*
* @return string
*/
public abstract function get_name();
/**
* Get description.
*
* @return string
*/
public abstract function get_description();
/**
* Get settings definitions.
*
* @return SettingsDefinition
*/
public abstract function get_settings_definition();
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Capability: CanRate class
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
/**
* Tag interface that informs if Service supports Shipment::insurance flag.
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
interface CanInsure
{
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Capability: CanRate class
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
/**
* Tag interface that informs if Service supports Sghipment::packed flag.
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
interface CanPack
{
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Capability: CanRate class
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
use VendorDHL\WPDesk\AbstractShipping\Rate\ShipmentRating;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Shipment;
/**
* Interface for rate shipment
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
interface CanRate
{
/**
* Rate shipment.
*
* @param SettingsValues $settings Settings.
* @param Shipment $shipment Shipment.
*
* @return ShipmentRating
*/
public function rate_shipment(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings, \VendorDHL\WPDesk\AbstractShipping\Shipment\Shipment $shipment);
/**
* Is rate enabled?
*
* @param SettingsValues $settings .
*
* @return bool
*/
public function is_rate_enabled(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings);
}

View File

@@ -0,0 +1,37 @@
<?php
/**
* Capability: CanRateToCollectionPoint class
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
use VendorDHL\WPDesk\AbstractShipping\CollectionPoints\CollectionPoint;
use VendorDHL\WPDesk\AbstractShipping\Rate\ShipmentRating;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Shipment;
/**
* Interface for rate shipment to collection point
*/
interface CanRateToCollectionPoint
{
/**
* Rate shipment to collection point.
*
* @param SettingsValues $settings Settings.
* @param Shipment $shipment Shipment.
* @param CollectionPoint $collection_point Collection point.
*
* @return ShipmentRating
*/
public function rate_shipment_to_collection_point(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings, \VendorDHL\WPDesk\AbstractShipping\Shipment\Shipment $shipment, \VendorDHL\WPDesk\AbstractShipping\CollectionPoints\CollectionPoint $collection_point);
/**
* Is rate to collection point enabled?
*
* @param SettingsValues $settings
*
* @return mixed
*/
public function is_rate_to_collection_point_enabled(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings);
}

View File

@@ -0,0 +1,17 @@
<?php
/**
* Capability: CanRate class
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
/**
* Tag interface that informs if Service supports SingleRate::delivery_date field.
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
interface CanReturnDeliveryDate
{
}

View File

@@ -0,0 +1,32 @@
<?php
/**
* Capability: CanTestSettings class
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
use VendorDHL\Psr\Log\LoggerInterface;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues;
/**
* Interface for checking connection to API.
*/
interface CanTestSettings
{
/**
* Pings API.
* Returns empty string on success or error message on failure.
*
* @param SettingsValues $settings .
* @param LoggerInterface $logger .
* @return string
*/
public function check_connection(\VendorDHL\WPDesk\AbstractShipping\Settings\SettingsValues $settings, \VendorDHL\Psr\Log\LoggerInterface $logger);
/**
* Returns field ID after which API Status field should be added.
*
* @return string
*/
public function get_field_before_api_status_field();
}

View File

@@ -0,0 +1,24 @@
<?php
/**
* Capability: HasSettings class.
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
namespace VendorDHL\WPDesk\AbstractShipping\ShippingServiceCapability;
use VendorDHL\WPDesk\AbstractShipping\Settings\SettingsDefinition;
/**
* Interface for get settings definition
*
* @package WPDesk\AbstractShipping\ShippingServiceCapability
*/
interface HasSettings
{
/**
* Get settings definition.
*
* @return SettingsDefinition
*/
public function get_settings_definition();
}

View File

@@ -0,0 +1,80 @@
<?php
namespace VendorDHL\WPDesk\AbstractShipping\Shop;
/**
* Define some helper functions.
*
* @TODO: move from AbstractShipping to AbstractWooCommerceShipping ?
*/
interface ShopSettings
{
/**
* Get countries.
*
* @return string[]
*/
public function get_countries();
/**
* Get EU countries.
*
* @return string[]
*/
public function get_eu_countries();
/**
* Get states.
*
* @param null|string $cc Country code.
*
* @return array|false
*/
public function get_states($cc = null);
/**
* Get WooCommerce country.
*
* @return string
*/
public function get_origin_country();
/**
* Get locale.
*
* @return string
*/
public function get_locale();
/**
* Get weight unit.
*
* @return string
*/
public function get_weight_unit();
/**
* Get WooCommerce currency.
*
* @return string
*/
public function get_currency();
/**
* Get default shop currency.
*
* @return string
*/
public function get_default_currency();
/**
* Get price rounding precision.
*
* @return int
*/
public function get_price_rounding_precision();
/**
* Is production?
*
* @return bool
*/
public function is_testing();
/**
* Is tax enabled?
*
* @return bool
*/
public function is_tax_enabled();
}

View File

@@ -0,0 +1,80 @@
<?php
/**
* UnitConversion: Lenght Conversion.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\UnitConversion;
use VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Dimensions;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Weight;
/**
* Can convert length between different measure types
*/
class UniversalDimension
{
private $unit_calc = [\VendorDHL\WPDesk\AbstractShipping\Shipment\Dimensions::DIMENSION_UNIT_IN => 25.4, \VendorDHL\WPDesk\AbstractShipping\Shipment\Dimensions::DIMENSION_UNIT_MM => 1, \VendorDHL\WPDesk\AbstractShipping\Shipment\Dimensions::DIMENSION_UNIT_CM => 10, \VendorDHL\WPDesk\AbstractShipping\Shipment\Dimensions::DIMENSION_UNIT_M => 1000];
/**
* Length.
*
* @var float
*/
private $length;
/**
* Precision.
*
* @var int
*/
private $precision;
/**
* LengthConverter constructor.
*
* @param float $length Length.
* @param string $from_unit From unit.
* @param int $precision .
*
* @throws UnitConversionException Dimension exception.
*/
public function __construct($length, $from_unit, $precision = 3)
{
$this->precision = $precision;
$this->length = $this->to_mm($length, $from_unit);
}
/**
* @param float $length .
* @param string $unit .
*
* @return false|float
* @throws UnitConversionException
*/
private function to_mm($length, $unit)
{
$unit = \strtoupper($unit);
if (isset($this->unit_calc[$unit])) {
$calc = $this->unit_calc[$unit];
return \round($length * $calc, $this->precision);
}
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException(\sprintf('Can\'t support "%s" unit', $unit));
}
/**
* Convert to target unit. Returns 0 if confused.
*
* @param string $to_unit Target unit.
* @param int $precision .
*
* @return float
*
* @throws UnitConversionException Dimension exception.
*/
public function as_unit_rounded($to_unit, $precision = 2)
{
$to_unit = \strtoupper($to_unit);
if (isset($this->unit_calc[$to_unit])) {
$calc = $this->unit_calc[$to_unit];
return \round($this->length / $calc, $precision);
}
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException(\__('Can\'t convert weight to target unit.', 'woocommerce-dhl'));
}
}

View File

@@ -0,0 +1,95 @@
<?php
/**
* UnitConversion: Weight Conversion.
*
* @package WPDesk\AbstractShipping\Shipment
*/
namespace VendorDHL\WPDesk\AbstractShipping\UnitConversion;
use VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException;
use VendorDHL\WPDesk\AbstractShipping\Shipment\Weight;
/**
* Can convert weight between different measure types
*/
class UniversalWeight
{
/**
* Weight.
*
* @var float
*/
private $weight;
const UNIT_CALC = [\VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_G => 1, \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_LB => 453.59237, \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_KG => 1000, \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_OZ => 28.34952];
/**
* @var int
*/
private $precision;
/**
* WeightConverter constructor.
*
* @param float $weight Weight.
* @param string $unit Unit.
* @param int $precision .
*
* @throws UnitConversionException Weight exception.
*/
public function __construct($weight, $unit, $precision = 3)
{
$this->precision = $precision;
$this->weight = $this->to_grams($weight, $unit);
}
/**
* Unify all units to grams.
*
* @param float $weight Weight.
* @param string $unit Unit.
*
* @return float
* @throws \WPDesk\AbstractShipping\Exception\UnitConversionException Unit
* Conversion.
*/
private function to_grams($weight, $unit)
{
$unit = \strtoupper($unit);
if (\VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_LBS === $unit) {
$unit = \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_LB;
}
if (\VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_G === $unit) {
return $weight;
}
$calc = self::UNIT_CALC[$unit];
switch ($unit) {
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_KG:
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_LB:
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_OZ:
return \round($weight * $calc, $this->precision);
}
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException(\sprintf('Can\'t support "%s" unit', $unit));
}
/**
* Convert to target unit. Returns 0 if confused.
*
* @param string $target_unit Target unit.
* @param int $precision .
*
* @return float
*
* @throws UnitConversionException Weight exception.
*/
public function as_unit_rounded($target_unit, $precision = 2)
{
$target_unit = \strtoupper($target_unit);
$calc = self::UNIT_CALC[$target_unit];
switch ($target_unit) {
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_G:
return $this->weight;
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_KG:
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_LB:
case \VendorDHL\WPDesk\AbstractShipping\Shipment\Weight::WEIGHT_UNIT_OZ:
return \round($this->weight / $calc, $precision);
default:
throw new \VendorDHL\WPDesk\AbstractShipping\Exception\UnitConversionException(\__('Can\'t convert weight to target unit.', 'woocommerce-dhl'));
}
}
}

View File

@@ -0,0 +1,45 @@
{
"name": "wpdesk\/soap-client-with-logger",
"description": "SOAP client with logger",
"license": "MIT",
"keywords": [
"soap",
"logger"
],
"homepage": "https:\/\/gitlab.com\/wpdesk\/soap-client-with-logger",
"authors": [
{
"name": "grola",
"email": "grola@wpdesk.net"
}
],
"prefer-stable": true,
"minimum-stability": "dev",
"require": {
"php": ">=5.6",
"psr\/log": "^1.1"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"phpcompatibility\/php-compatibility": "^9.1"
},
"autoload": {
"psr-4": {
"VendorDHL\\WPDesk\\SOAP\\": "src\/SOAP"
}
},
"autoload-dev": {
"classmap": [
"tests\/unit"
]
},
"scripts": {
"phpcs": "phpcs",
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
}
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* SOAP Client With Logger
*/
namespace VendorDHL\WPDesk\SOAP;
use VendorDHL\Psr\Log\LoggerInterface;
use VendorDHL\Psr\Log\NullLogger;
/**
* Decorator for SOAP Client.
* Can do SOAP calls and log request and response.
*/
class SoapClientWithLogger
{
/**
* @var \SoapClient
*/
private $soapClient;
/**
* @var LoggerInterface
*/
private $logger;
/**
* @var int
*/
private $max_response_log_entry_size;
/**
* @param \SoapClient $soapClient
* @param LoggerInterface $logger
* @param int $max_response_log_entry_size Maximum response log entry size. -1 for unlimited.
*/
public function __construct(\SoapClient $soapClient, \VendorDHL\Psr\Log\LoggerInterface $logger, $max_response_log_entry_size = 2000)
{
$this->soapClient = $soapClient;
$this->logger = $logger;
$this->max_response_log_entry_size = $max_response_log_entry_size;
}
/**
* @param string $function_name
* @param array $arguments
*
* @return mixed
*/
public function __call($function_name, $arguments)
{
try {
return \call_user_func_array([$this->soapClient, $function_name], $arguments);
} finally {
$this->logger->info($this->soapClient->__getLastRequestHeaders() . $this->soapClient->__getLastRequest(), ['type' => 'REQUEST']);
$this->logger->info($this->soapClient->__getLastResponseHeaders() . ($this->max_response_log_entry_size === -1 ? $this->soapClient->__getLastResponse() : \substr($this->soapClient->__getLastResponse(), 0, $this->max_response_log_entry_size) . '... truncated at character ' . $this->max_response_log_entry_size), ['type' => 'RESPONSE']);
}
}
}

View File

@@ -0,0 +1,47 @@
{
"name": "wpdesk\/wp-basic-requirements",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"php": ">=5.5",
"phpunit\/phpunit": "<7",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"wimg\/php-compatibility": "^8"
},
"autoload": {},
"autoload-dev": {
"classmap": [
"src",
"tests"
]
},
"extra": {
"text-domain": "wp-basic-requirements",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po",
"en_AU": "en_AU.po",
"en_CA": "en_CA.po",
"en_GB": "en_GB.po",
"de_DE": "de_DE.po"
}
},
"scripts": {
"phpcs": "phpcs",
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage",
"docs": "apigen generate"
}
}

View File

@@ -0,0 +1,602 @@
<?php
namespace VendorDHL;
if (!\interface_exists('VendorDHL\\WPDesk_Requirement_Checker')) {
require_once __DIR__ . '/Requirement_Checker.php';
}
if (!\class_exists('VendorDHL\\WPDesk_Basic_Requirement_Checker')) {
/**
* Checks requirements for plugin
* have to be compatible with PHP 5.3.x
*/
class WPDesk_Basic_Requirement_Checker implements \VendorDHL\WPDesk_Requirement_Checker
{
const EXTENSION_NAME_OPENSSL = 'openssl';
const HOOK_ADMIN_NOTICES_ACTION = 'admin_notices';
const HOOK_PLUGIN_DEACTIVATED_ACTION = 'deactivated_plugin';
const HOOK_PLUGIN_ACTIVATED_ACTION = 'activated_plugin';
const PLUGIN_INFO_KEY_NICE_NAME = 'nice_name';
const PLUGIN_INFO_KEY_NAME = 'name';
const PLUGIN_INFO_VERSION = 'version';
const PLUGIN_INFO_FAKE_REQUIRED_MINIMUM_VERSION = '0.0';
const PLUGIN_INFO_APPEND_PLUGIN_DATA = 'required_version';
const PLUGIN_INFO_TRANSIENT_NAME = 'wpdesk_requirements_plugins_data';
const CACHE_TIME = 16;
const EXPIRATION_TIME = 'expiration_time';
const PLUGINS = 'plugins';
/** @var string */
protected $plugin_name;
/** @var string */
private $plugin_file;
/** @var string */
private $min_php_version;
/** @var string */
private $min_wp_version;
/** @var string|null */
private $min_wc_version = null;
/** @var int|null */
private $min_openssl_version = null;
/** @var array */
protected $plugin_require;
/** @var bool */
protected $should_check_plugin_versions = \false;
/** @var array */
private $module_require;
/** @var array */
private $setting_require;
/** @var array */
protected $notices;
/** @var @string */
private $text_domain;
/**
* @var mixed|true
*/
private $use_transients;
/**
* @param string $plugin_file
* @param string $plugin_name
* @param string $text_domain
* @param string $php_version
* @param string $wp_version
* @param bool $use_transients
*/
public function __construct($plugin_file, $plugin_name, $text_domain, $php_version, $wp_version, $use_transients = \true)
{
$this->plugin_file = $plugin_file;
$this->plugin_name = $plugin_name;
$this->text_domain = $text_domain;
$this->use_transients = $use_transients;
$this->set_min_php_require($php_version);
$this->set_min_wp_require($wp_version);
$this->plugin_require = array();
$this->module_require = array();
$this->setting_require = array();
$this->notices = array();
}
/**
* @param string $version
*
* @return $this
*/
public function set_min_php_require($version)
{
$this->min_php_version = $version;
return $this;
}
/**
* @param string $version
*
* @return $this
*/
public function set_min_wp_require($version)
{
$this->min_wp_version = $version;
return $this;
}
/**
* @param string $version
*
* @return $this
*/
public function set_min_wc_require($version)
{
$this->min_wc_version = $version;
return $this;
}
/**
* @param $version
*
* @return $this
*/
public function set_min_openssl_require($version)
{
$this->min_openssl_version = $version;
return $this;
}
/**
* @param string $plugin_name Name in wp format dir/file.php
* @param string $nice_plugin_name Nice plugin name for better looks in notice
* @param string $plugin_require_version required plugin minimum version
*
* @return $this
*/
public function add_plugin_require($plugin_name, $nice_plugin_name = null, $plugin_require_version = null)
{
if ($plugin_require_version) {
$this->should_check_plugin_versions = \true;
}
$this->plugin_require[$plugin_name] = array(self::PLUGIN_INFO_KEY_NAME => $plugin_name, self::PLUGIN_INFO_KEY_NICE_NAME => $nice_plugin_name === null ? $plugin_name : $nice_plugin_name, self::PLUGIN_INFO_VERSION => $plugin_require_version === null ? self::PLUGIN_INFO_FAKE_REQUIRED_MINIMUM_VERSION : $plugin_require_version);
return $this;
}
/**
* Add plugin to require list. Plugin is from repository so we can ask for installation.
*
* @param string $plugin_name Name in wp format dir/file.php
* @param string $version Required version of the plugin.
* @param string $nice_plugin_name Nice plugin name for better looks in notice
*
* @return $this
*/
public function add_plugin_repository_require($plugin_name, $version, $nice_plugin_name = null)
{
$this->plugin_require[$plugin_name] = array(self::PLUGIN_INFO_KEY_NAME => $plugin_name, self::PLUGIN_INFO_VERSION => $version, 'repository_url' => 'http://downloads.wordpress.org/plugin/' . \dirname($plugin_name) . '.latest-stable.zip', self::PLUGIN_INFO_KEY_NICE_NAME => $nice_plugin_name === null ? $plugin_name : $nice_plugin_name);
return $this;
}
/**
* @param string $module_name
* @param string $nice_name Nice module name for better looks in notice
*
* @return $this
*/
public function add_php_module_require($module_name, $nice_name = null)
{
if ($nice_name === null) {
$this->module_require[$module_name] = $module_name;
} else {
$this->module_require[$module_name] = $nice_name;
}
return $this;
}
/**
* @param string $setting
* @param mixed $value
*
* @return $this
*/
public function add_php_setting_require($setting, $value)
{
$this->setting_require[$setting] = $value;
return $this;
}
/**
* Returns true if are requirements are met.
*
* @return bool
*/
public function are_requirements_met()
{
$this->notices = $this->prepare_requirement_notices();
return \count($this->notices) === 0;
}
/**
* @return array
*/
private function prepare_requirement_notices()
{
$notices = array();
if (!self::is_php_at_least($this->min_php_version)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run on PHP versions older than %s. Please contact your host and ask them to upgrade.', $this->get_text_domain()), \esc_html($this->plugin_name), $this->min_php_version));
}
if (!self::is_wp_at_least($this->min_wp_version)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run on WordPress versions older than %s. Please update WordPress.', $this->get_text_domain()), \esc_html($this->plugin_name), $this->min_wp_version));
}
if ($this->min_wc_version !== null && $this->can_check_plugin_version() && !self::is_wc_at_least($this->min_wc_version)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run on WooCommerce versions older than %s. Please update WooCommerce.', $this->get_text_domain()), \esc_html($this->plugin_name), $this->min_wc_version));
}
if ($this->min_openssl_version !== null && !self::is_open_ssl_at_least($this->min_openssl_version)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run without OpenSSL module version at least %s. Please update OpenSSL module.', $this->get_text_domain()), \esc_html($this->plugin_name), '0x' . \dechex($this->min_openssl_version)));
}
$notices = $this->append_plugin_require_notices($notices);
$notices = $this->append_module_require_notices($notices);
$notices = $this->append_settings_require_notices($notices);
if ($this->should_check_plugin_versions) {
$notices = $this->check_minimum_require_plugins_version_and_append_notices($notices);
}
return $notices;
}
/**
* @param $min_version
*
* @return mixed
*/
public static function is_php_at_least($min_version)
{
return \version_compare(\PHP_VERSION, $min_version, '>=');
}
/**
* Prepares message in html format
*
* @param string $message
*
* @return string
*/
protected function prepare_notice_message($message)
{
return '<div class="error"><p>' . $message . '</p></div>';
}
public function get_text_domain()
{
return $this->text_domain;
}
/**
* @param string $min_version
*
* @return bool
*/
public static function is_wp_at_least($min_version)
{
return \version_compare(\get_bloginfo('version'), $min_version, '>=');
}
/**
* Are plugins loaded so we can check the version
*
* @return bool
*/
private function can_check_plugin_version()
{
return \did_action('plugins_loaded') > 0;
}
/**
* Checks if plugin is active and have designated version. Needs to be enabled in deferred way.
*
* @param string $min_version
*
* @return bool
*/
public static function is_wc_at_least($min_version)
{
return \defined('WC_VERSION') && \version_compare(\WC_VERSION, $min_version, '>=');
}
/**
* Checks if ssl version is valid
*
* @param int $required_version Version in hex. Version 9.6 is 0x000906000
*
* @return bool
* @see https://www.openssl.org/docs/man1.1.0/crypto/OPENSSL_VERSION_NUMBER.html
*
*/
public static function is_open_ssl_at_least($required_version)
{
return \defined('OPENSSL_VERSION_NUMBER') && \OPENSSL_VERSION_NUMBER > (int) $required_version;
}
/**
* @param $notices array
*
* @return array
*/
private function check_minimum_require_plugins_version_and_append_notices($notices)
{
$required_plugins = $this->retrieve_required_plugins_data();
if (\count($required_plugins) > 0) {
foreach ($required_plugins as $plugin) {
if (\version_compare($plugin['Version'], $plugin[self::PLUGIN_INFO_APPEND_PLUGIN_DATA], '<')) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%1$s&#8221; plugin requires at least %2$s version of %3$s to work correctly. Please update it to its latest release.', $this->get_text_domain()), \esc_html($this->plugin_name), $plugin[self::PLUGIN_INFO_APPEND_PLUGIN_DATA], $plugin['Name']));
}
}
}
return $notices;
}
/**
* Check the plugins directory and retrieve all plugin files with plugin data.
*
* @param bool $use_transients
*
* @return array In format [ 'plugindir/pluginfile.php' => ['Name' => 'Plugin Name', 'Version' => '1.0.1', ...], ]
*/
private static function retrieve_plugins_data_in_transient($use_transients = \true)
{
$current_time = \time();
$plugins = self::get_plugins_data_from_cache($use_transients, $current_time);
if ($plugins === \false) {
static $never_executed = \true;
if ($never_executed) {
$never_executed = \false;
/** Required when WC starts later and these data should be in cache */
\add_filter('extra_plugin_headers', function ($headers = array()) {
$headers[] = 'WC tested up to';
$headers[] = 'WC requires at least';
$headers[] = 'Woo';
return \array_unique($headers);
});
}
if (!\function_exists('get_plugins')) {
require_once \ABSPATH . '/wp-admin/includes/plugin.php';
}
$plugins = \function_exists('get_plugins') ? \get_plugins() : array();
self::update_plugins_data_in_cache($plugins, $use_transients, $current_time);
}
return $plugins;
}
/**
* @param bool $use_transients
* @param int $current_time
*
* @return array|false
*/
private static function get_plugins_data_from_cache($use_transients, $current_time)
{
if ($use_transients) {
return \get_transient(self::PLUGIN_INFO_TRANSIENT_NAME);
} else {
$plugins_option_value = \get_option(self::PLUGIN_INFO_TRANSIENT_NAME);
if (\is_array($plugins_option_value) && isset($plugins_option_value[self::EXPIRATION_TIME], $plugins_option_value[self::PLUGINS]) && (int) $plugins_option_value[self::EXPIRATION_TIME] > $current_time) {
return $plugins_option_value[self::PLUGINS];
}
}
return \false;
}
/**
* @param array $plugins
* @param bool $use_transients
* @param int $current_time
*/
private static function update_plugins_data_in_cache($plugins, $use_transients, $current_time)
{
if ($use_transients) {
\set_transient(self::PLUGIN_INFO_TRANSIENT_NAME, $plugins, self::CACHE_TIME);
} else {
\update_option(self::PLUGIN_INFO_TRANSIENT_NAME, array(self::EXPIRATION_TIME => $current_time + self::CACHE_TIME, self::PLUGINS => $plugins));
}
}
/**
* Check the plugins directory and retrieve all required plugin files with plugin data.
*
* @return array In format [ 'plugindir/pluginfile.php' => ['Name' => 'Plugin Name', 'Version' => '1.0.1', 'required_version' => '1.0.2']... ]
*/
private function retrieve_required_plugins_data()
{
$require_plugins = array();
$plugins = self::retrieve_plugins_data_in_transient($this->use_transients);
if (\is_array($plugins)) {
if (\count($plugins) > 0) {
if (!empty($this->plugin_require)) {
foreach ($this->plugin_require as $plugin) {
$plugin_file_name = $plugin[self::PLUGIN_INFO_KEY_NAME];
$plugin_version = $plugin[self::PLUGIN_INFO_VERSION];
if (self::is_wp_plugin_active($plugin_file_name)) {
$require_plugins[$plugin_file_name] = $plugins[$plugin_file_name];
$require_plugins[$plugin_file_name][self::PLUGIN_INFO_APPEND_PLUGIN_DATA] = $plugin_version;
}
}
}
}
}
return $require_plugins;
}
/**
* @param array $notices
*
* @return array
*/
private function append_plugin_require_notices($notices)
{
if (\count($this->plugin_require) > 0) {
foreach ($this->plugin_require as $plugin_name => $plugin_info) {
$notice = null;
if (isset($plugin_info['repository_url'])) {
$notice = $this->prepare_plugin_repository_require_notice($plugin_info);
} elseif (!self::is_wp_plugin_active($plugin_name)) {
$notice = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run without %s active. Please install and activate %s plugin.', $this->get_text_domain()), \esc_html($this->plugin_name), \esc_html(\basename($plugin_info[self::PLUGIN_INFO_KEY_NICE_NAME])), \esc_html(\basename($plugin_info[self::PLUGIN_INFO_KEY_NICE_NAME]))));
}
if ($notice !== null) {
$notices[] = $notice;
}
}
}
return $notices;
}
/**
* Prepares WP install url and injects info about plugin to the WP update engine.
*
* @param array $plugin_info
*
* @return string
*/
private function prepare_plugin_repository_install_url($plugin_info)
{
$slug = \basename($plugin_info[self::PLUGIN_INFO_KEY_NAME]);
$install_url = \self_admin_url('update.php?action=install-plugin&plugin=' . $slug);
if (\function_exists('wp_nonce_url') && \function_exists('wp_create_nonce')) {
$install_url = \wp_nonce_url($install_url, 'install-plugin_' . $slug);
}
\add_filter('plugins_api', function ($api, $action, $args) use($plugin_info, $slug) {
if ('plugin_information' !== $action || \false !== $api || !isset($args->slug) || $slug !== $args->slug) {
return $api;
}
$api = new \stdClass();
$api->name = $plugin_info['nice_name'];
// self in closures requires 5.4
$api->version = '';
$api->download_link = \esc_url($plugin_info['repository_url']);
// self in closures requires 5.4
return $api;
}, 10, 3);
return $install_url;
}
/**
* @param array $plugin_info Internal required plugin info data.
*
* @return string|null Return null if no notice is needed.
*/
private function prepare_plugin_repository_require_notice($plugin_info)
{
$name = $plugin_info[self::PLUGIN_INFO_KEY_NAME];
$nice_name = $plugin_info[self::PLUGIN_INFO_KEY_NICE_NAME];
if (!self::is_wp_plugin_active($name)) {
if (!self::is_wp_plugin_installed($name, $this->use_transients)) {
$install_url = $this->prepare_plugin_repository_install_url($plugin_info);
return $this->prepare_notice_message(\sprintf(\wp_kses(\__('The &#8220;%s&#8221; plugin requires free %s plugin. <a href="%s">Install %s</a>', $this->get_text_domain()), array('a' => array('href' => array()))), $this->plugin_name, $nice_name, \esc_url($install_url), $nice_name));
}
$activate_url = 'plugins.php?action=activate&plugin=' . \urlencode($plugin_info[self::PLUGIN_INFO_KEY_NAME]) . '&plugin_status=all&paged=1&s';
if (\function_exists('wp_create_nonce')) {
$activate_url .= '&_wpnonce=' . \urlencode(\wp_create_nonce('activate-plugin_' . $name));
}
return $this->prepare_notice_message(\sprintf(\wp_kses(\__('The &#8220;%s&#8221; plugin requires activating %s plugin. <a href="%s">Activate %s</a>', $this->get_text_domain()), array('a' => array('href' => array()))), $this->plugin_name, $nice_name, \esc_url(\admin_url($activate_url)), $nice_name));
}
return null;
}
/**
* Checks if plugin is active. Needs to be used in deferred way.
*
* @param string $plugin_file
*
* @return bool
*/
public static function is_wp_plugin_active($plugin_file)
{
$active_plugins = (array) \get_option('active_plugins', array());
if (\is_multisite()) {
$active_plugins = \array_merge($active_plugins, \get_site_option('active_sitewide_plugins', array()));
}
return \in_array($plugin_file, $active_plugins) || \array_key_exists($plugin_file, $active_plugins);
}
/**
* Checks if plugin is installed. Needs to be enabled in deferred way.
*
* @param string $plugin_file
* @param bool $use_transients
*
* @return bool
*/
public static function is_wp_plugin_installed($plugin_file, $use_transients = \false)
{
$plugins_data = self::retrieve_plugins_data_in_transient($use_transients);
return \array_key_exists($plugin_file, (array) $plugins_data);
}
/**
* @param array $notices
*
* @return array
*/
private function append_module_require_notices($notices)
{
if (\count($this->module_require) > 0) {
foreach ($this->module_require as $module_name => $nice_module_name) {
if (!self::is_module_active($module_name)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run without %s PHP module installed. Please contact your host and ask them to install %s.', $this->get_text_domain()), \esc_html($this->plugin_name), \esc_html(\basename($nice_module_name)), \esc_html(\basename($nice_module_name))));
}
}
}
return $notices;
}
/**
* @param string $name
*
* @return bool
*/
public static function is_module_active($name)
{
return \extension_loaded($name);
}
/**
* @param array $notices
*
* @return array
*/
private function append_settings_require_notices($notices)
{
if (\count($this->setting_require) > 0) {
foreach ($this->setting_require as $setting => $value) {
if (!self::is_setting_set($setting, $value)) {
$notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin cannot run without %s PHP setting set to %s. Please contact your host and ask them to set %s.', $this->get_text_domain()), \esc_html($this->plugin_name), \esc_html(\basename($setting)), \esc_html(\basename($value)), \esc_html(\basename($setting))));
}
}
}
return $notices;
}
/**
* @param string $name
* @param mixed $value
*
* @return bool
*/
public static function is_setting_set($name, $value)
{
return \ini_get($name) === (string) $value;
}
/**
* @return void
*
* @deprecated use render_notices or disable_plugin
*/
public function disable_plugin_render_notice()
{
\add_action(self::HOOK_ADMIN_NOTICES_ACTION, array($this, 'handle_render_notices_action'));
}
/**
* Renders requirement notices in admin panel
*
* @return void
*/
public function render_notices()
{
\add_action(self::HOOK_ADMIN_NOTICES_ACTION, array($this, 'handle_render_notices_action'));
}
/**
* Renders requirement notices in admin panel
*
* @return void
*/
public function disable_plugin()
{
\add_action(self::HOOK_ADMIN_NOTICES_ACTION, array($this, 'handle_deactivate_action'));
}
/**
* @return void
* @internal Do not use as public. Public only for wp action.
*
*/
public function handle_deactivate_action()
{
if (isset($this->plugin_file)) {
\deactivate_plugins(\plugin_basename($this->plugin_file));
$this->clear_plugin_info_data();
}
}
/**
* Triggers the transient delete after plugin deactivated
*
* @return void
*/
public function transient_delete_on_plugin_version_changed()
{
\add_action(self::HOOK_PLUGIN_DEACTIVATED_ACTION, array($this, 'clear_plugin_info_data'));
\add_action(self::HOOK_PLUGIN_ACTIVATED_ACTION, array($this, 'clear_plugin_info_data'));
}
/**
* Handles the transient delete
*
* @return void
*/
public function clear_plugin_info_data()
{
\delete_transient(self::PLUGIN_INFO_TRANSIENT_NAME);
\delete_option(self::PLUGIN_INFO_TRANSIENT_NAME);
}
/**
* Should be called as WordPress action
*
* @return void
* @internal Do not use as public. Public only for wp action.
*
*/
public function handle_render_notices_action()
{
foreach ($this->notices as $notice) {
echo $notice;
}
}
}
}

View File

@@ -0,0 +1,62 @@
<?php
namespace VendorDHL;
if (!\class_exists('VendorDHL\\Basic_Requirement_Checker')) {
require_once __DIR__ . '/Basic_Requirement_Checker.php';
}
if (!\class_exists('VendorDHL\\WPDesk_Basic_Requirement_Checker_With_Update_Disable')) {
require_once __DIR__ . '/Basic_Requirement_Checker_With_Update_Disable.php';
}
/**
* Falicitates createion of requirement checker
*/
class WPDesk_Basic_Requirement_Checker_Factory
{
const LIBRARY_TEXT_DOMAIN = 'woocommerce-dhl';
/**
* Creates a simplest possible version of requirement checker.
*
* @param string $plugin_file
* @param string $plugin_name
* @param string|null $text_domain Text domain to use. If null try to use library text domain.
*
* @return WPDesk_Requirement_Checker
*/
public function create_requirement_checker($plugin_file, $plugin_name, $text_domain = null)
{
return new \VendorDHL\WPDesk_Basic_Requirement_Checker($plugin_file, $plugin_name, $text_domain, null, null);
}
/**
* Creates a requirement checker according to given requirements array info.
*
* @param string $plugin_file
* @param string $plugin_name
* @param string $text_domain Text domain to use. If null try to use library text domain.
* @param array $requirements Requirements array as given by plugin.
*
* @return WPDesk_Requirement_Checker
*/
public function create_from_requirement_array($plugin_file, $plugin_name, $requirements, $text_domain = null)
{
$requirements_checker = new \VendorDHL\WPDesk_Basic_Requirement_Checker_With_Update_Disable($plugin_file, $plugin_name, $text_domain, $requirements['php'], $requirements['wp'], (bool) \wp_using_ext_object_cache());
if (isset($requirements['plugins'])) {
foreach ($requirements['plugins'] as $requirement) {
$version = isset($requirement['version']) ? $requirement['version'] : null;
$requirements_checker->add_plugin_require($requirement['name'], $requirement['nice_name'], $version);
}
$requirements_checker->transient_delete_on_plugin_version_changed();
}
if (isset($requirements['repo_plugins'])) {
foreach ($requirements['repo_plugins'] as $requirement) {
$requirements_checker->add_plugin_repository_require($requirement['name'], $requirement['version'], $requirement['nice_name']);
}
}
if (isset($requirements['modules'])) {
foreach ($requirements['modules'] as $requirement) {
$requirements_checker->add_php_module_require($requirement['name'], $requirement['nice_name']);
}
}
return $requirements_checker;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace VendorDHL;
if (!\class_exists('VendorDHL\\WPDesk_Basic_Requirement_Checker')) {
require_once __DIR__ . '/Basic_Requirement_Checker.php';
}
if (!\class_exists('VendorDHL\\WPDesk_Basic_Requirement_Checker_With_Update_Disable')) {
/**
* Checks requirements for plugin. When required plugin is updated right now, then say that requirements are not met temporary.
* have to be compatible with PHP 5.2.x
*/
class WPDesk_Basic_Requirement_Checker_With_Update_Disable extends \VendorDHL\WPDesk_Basic_Requirement_Checker
{
/**
* Returns true if are requirements are met.
*
* @return bool
*/
public function are_requirements_met()
{
$has_been_met = parent::are_requirements_met();
if (!$has_been_met) {
return $has_been_met;
}
foreach ($this->plugin_require as $name => $plugin_info) {
if ($this->is_currently_updated($name)) {
$nice_name = $plugin_info[self::PLUGIN_INFO_KEY_NICE_NAME];
$this->notices[] = $this->prepare_notice_message(\sprintf(\__('The &#8220;%s&#8221; plugin is temporarily disabled since the required %s plugin is being upgraded.', $this->get_text_domain()), $this->plugin_name, $nice_name, $nice_name));
}
}
return \count($this->notices) === 0;
}
/**
* Is plugin upgrading right now?
*
* @param string $name
*
* @return bool
*/
private function is_currently_updated($name)
{
return isset($_GET['action']) && $_GET['action'] === 'upgrade-plugin' && $_GET['plugin'] === $name;
}
}
}

View File

@@ -0,0 +1,74 @@
<?php
namespace VendorDHL;
/**
* Checks requirements for plugin
* have to be compatible with PHP 5.2.x
*/
interface WPDesk_Requirement_Checker
{
/**
* @param string $version
*
* @return $this
*/
public function set_min_php_require($version);
/**
* @param string $version
*
* @return $this
*/
public function set_min_wp_require($version);
/**
* @param string $version
*
* @return $this
*/
public function set_min_wc_require($version);
/**
* @param $version
*
* @return $this
*/
public function set_min_openssl_require($version);
/**
* @param string $plugin_name
* @param string $nice_plugin_name Nice plugin name for better looks in notice
*
* @return $this
*/
public function add_plugin_require($plugin_name, $nice_plugin_name = null);
/**
* @param string $module_name
* @param string $nice_name Nice module name for better looks in notice
*
* @return $this
*/
public function add_php_module_require($module_name, $nice_name = null);
/**
* @param string $setting
* @param mixed $value
*
* @return $this
*/
public function add_php_setting_require($setting, $value);
/**
* @return bool
*/
public function are_requirements_met();
/**
* @return void
*/
public function disable_plugin_render_notice();
/**
* @return void
*/
public function render_notices();
/**
* Renders requirement notices in admin panel
*
* @return void
*/
public function disable_plugin();
}

View File

@@ -0,0 +1,17 @@
<?php
namespace VendorDHL;
interface WPDesk_Requirement_Checker_Factory
{
/**
* @param $plugin_file
* @param $plugin_name
* @param $text_domain
* @param $php_version
* @param $wp_version
*
* @return WPDesk_Requirement_Checker
*/
public function create_requirement_checker($plugin_file, $plugin_name, $text_domain);
}

View File

@@ -0,0 +1,36 @@
{
"name": "wpdesk\/wp-builder",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"require": {
"php": ">=5.5"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"wimg\/php-compatibility": "^8"
},
"autoload": {
"psr-4": {
"VendorDHL\\WPDesk\\PluginBuilder\\": "src\/"
},
"classmap": [
"src\/Plugin\/WithoutNamespace"
]
},
"autoload-dev": {},
"scripts": {
"phpcs": "phpcs",
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\BuildDirector;
use VendorDHL\WPDesk\PluginBuilder\Builder\AbstractBuilder;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
use VendorDHL\WPDesk\PluginBuilder\Storage\StorageFactory;
class LegacyBuildDirector
{
/** @var AbstractBuilder */
private $builder;
public function __construct(\VendorDHL\WPDesk\PluginBuilder\Builder\AbstractBuilder $builder)
{
$this->builder = $builder;
}
/**
* Builds plugin
*/
public function build_plugin()
{
$this->builder->build_plugin();
$this->builder->init_plugin();
$storage = new \VendorDHL\WPDesk\PluginBuilder\Storage\StorageFactory();
$this->builder->store_plugin($storage->create_storage());
}
/**
* Returns built plugin
*
* @return AbstractPlugin
*/
public function get_plugin()
{
return $this->builder->get_plugin();
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Builder;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
use VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage;
abstract class AbstractBuilder
{
/**
* Create plugin class
*/
public function build_plugin()
{
}
/**
* Store plugin class in some kind of storage
*/
public function store_plugin(\VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage $storage)
{
}
/**
* Init plugin internal structure
*/
public function init_plugin()
{
}
/**
* Return built plugin
* @return AbstractPlugin
*/
abstract function get_plugin();
/**
* Set settings class in plugin
*
* @param $settings
*/
public function set_settings($settings)
{
}
/**
* Set view class in plugin
*
* @param $view
*/
public function set_view($view)
{
}
/**
* Set tracker class in plugin
*
* @param $tracker
*/
public function set_tracker($tracker)
{
}
/**
* Set helper class in plugin
*
* @param $helper
*/
public function set_helper($helper)
{
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Builder;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
use VendorDHL\WPDesk\PluginBuilder\Plugin\ActivationAware;
use VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage;
/**
* Builder that have info about activations
*
* Warning: We can't extend InfoBuilder.php as some old plugins(without wp-flow) will load the old version od InfoBuilder class that have private plugin property.
*
* @package WPDesk\PluginBuilder\Builder
*/
class InfoActivationBuilder extends \VendorDHL\WPDesk\PluginBuilder\Builder\AbstractBuilder
{
const FILTER_PLUGIN_CLASS = 'wp_builder_plugin_class';
const HOOK_BEFORE_PLUGIN_INIT = 'wp_builder_before_plugin_init';
const HOOK_AFTER_PLUGIN_INIT = 'wp_builder_before_init';
/** @var AbstractPlugin */
private $plugin;
/** @var \WPDesk_Buildable */
private $info;
/** @var string */
protected $storage_id;
/**
* @var bool
*/
private $is_active;
/**
* @param \WPDesk_Buildable $info
* @param bool $is_active
*/
public function __construct(\VendorDHL\WPDesk_Buildable $info, $is_active)
{
$this->info = $info;
$this->storage_id = $info->get_class_name();
$this->is_active = $is_active;
}
/**
* Builds instance of plugin
*/
public function build_plugin()
{
$class_name = \apply_filters(self::FILTER_PLUGIN_CLASS, $this->info->get_class_name());
/** @var AbstractPlugin $plugin */
$this->plugin = new $class_name($this->info);
if ($this->plugin instanceof \VendorDHL\WPDesk\PluginBuilder\Plugin\ActivationAware && $this->is_active) {
$this->plugin->set_active();
}
return $this->plugin;
}
public function store_plugin(\VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage $storage)
{
$storage->add_to_storage($this->storage_id, $this->plugin);
}
public function init_plugin()
{
\do_action(self::HOOK_BEFORE_PLUGIN_INIT, $this->plugin);
$this->plugin->init();
\do_action(self::HOOK_AFTER_PLUGIN_INIT, $this->plugin);
}
/**
* @return AbstractPlugin
*/
public function get_plugin()
{
return $this->plugin;
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Builder;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
use VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage;
/**
* @deprecated Should not be used as some old plugins are using it and we can't touch this.
*
* @package WPDesk\PluginBuilder\Builder
*/
class InfoBuilder extends \VendorDHL\WPDesk\PluginBuilder\Builder\AbstractBuilder
{
const FILTER_PLUGIN_CLASS = 'wp_builder_plugin_class';
const HOOK_BEFORE_PLUGIN_INIT = 'wp_builder_before_plugin_init';
const HOOK_AFTER_PLUGIN_INIT = 'wp_builder_before_init';
/** @var AbstractPlugin */
private $plugin;
/** @var \WPDesk_Buildable */
private $info;
/** @var string */
protected $storage_id;
public function __construct(\VendorDHL\WPDesk_Buildable $info)
{
$this->info = $info;
$this->storage_id = $info->get_class_name();
}
/**
* Builds instance of plugin
*/
public function build_plugin()
{
$class_name = \apply_filters(self::FILTER_PLUGIN_CLASS, $this->info->get_class_name());
/** @var AbstractPlugin $plugin */
$this->plugin = new $class_name($this->info);
}
public function store_plugin(\VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage $storage)
{
$storage->add_to_storage($this->storage_id, $this->plugin);
}
public function init_plugin()
{
\do_action(self::HOOK_BEFORE_PLUGIN_INIT, $this->plugin);
$this->plugin->init();
\do_action(self::HOOK_AFTER_PLUGIN_INIT, $this->plugin);
}
/**
* @return AbstractPlugin
*/
public function get_plugin()
{
return $this->plugin;
}
}

View File

@@ -0,0 +1,203 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* Base plugin with most basic functionalities used by every WPDesk plugin.
*
*
* Known issues:
*
* The class name is too generic but can't be changed as it would introduce a major incompatibility for most of the plugins.
* The $plugin_url, $docs_url and most other fields should be removed as they only litter the place but for compatibility reasons we can't do it right now.
* Hook methods should be moved to external classes but for compatibility reasons we can't do it right now.
*/
abstract class AbstractPlugin extends \VendorDHL\WPDesk\PluginBuilder\Plugin\SlimPlugin
{
/**
* Most info about plugin internals.
*
* @var \WPDesk_Plugin_Info
*/
protected $plugin_info;
/**
* Unique string for this plugin in [a-z_]+ format.
*
* @var string
*/
protected $plugin_namespace;
/**
* Absolute URL to the plugin dir.
*
* @var string
*/
protected $plugin_url;
/**
* Absolute URL to the plugin docs.
*
* @var string
*/
protected $docs_url;
/**
* Absolute URL to the plugin settings url.
*
* @var string
*/
protected $settings_url;
/**
* Support URL.
*
* @var string
*/
protected $support_url;
/**
* AbstractPlugin constructor.
*
* @param \WPDesk_Plugin_Info $plugin_info
*/
public function __construct($plugin_info)
{
$this->plugin_info = $plugin_info;
$this->plugin_namespace = \strtolower($plugin_info->get_plugin_dir());
$this->plugin_url = $this->plugin_info->get_plugin_url();
$this->init_base_variables();
}
/**
* Initialize internal state of the plugin.
*
* @return void
* @deprecated Just use __construct to initialize plugin internal state.
*
*/
public function init_base_variables()
{
}
/**
* Initializes plugin external state.
*
* The plugin internal state is initialized in the constructor and the plugin should be internally consistent after creation.
* The external state includes hooks execution, communication with other plugins, integration with WC etc.
*
* @return void
*/
public function init()
{
$this->hooks();
}
/**
* Returns absolute path to the plugin dir.
*
* @return string
*/
public function get_plugin_file_path()
{
return $this->plugin_info->get_plugin_file_name();
}
/**
* Returns plugin text domain.
*
* @return string
*/
public function get_text_domain()
{
return $this->plugin_info->get_text_domain();
}
/**
* Returns unique string for plugin in [a-z_]+ format. Can be used as plugin id in various places like plugin slug etc.
*
* @return string
*/
public function get_namespace()
{
return $this->plugin_namespace;
}
/**
* Returns plugin absolute URL.
*
* @return string
*/
public function get_plugin_url()
{
return \esc_url(\trailingslashit($this->plugin_url));
}
/**
* Returns plugin absolute URL to dir with front end assets.
*
* @return string
*/
public function get_plugin_assets_url()
{
return \esc_url(\trailingslashit($this->get_plugin_url() . 'assets'));
}
/**
* @return $this
* @deprecated For backward compatibility.
*
*/
public function get_plugin()
{
return $this;
}
/**
* Integrate with WordPress and with other plugins using action/filter system.
*
* @return void
*/
protected function hooks()
{
\add_action('admin_enqueue_scripts', [$this, 'admin_enqueue_scripts']);
\add_action('wp_enqueue_scripts', [$this, 'wp_enqueue_scripts']);
\add_action('plugins_loaded', [$this, 'load_plugin_text_domain']);
\add_filter('plugin_action_links_' . \plugin_basename($this->get_plugin_file_path()), [$this, 'links_filter']);
}
/**
* Initialize plugin test domain. This is a hook function. Do not execute directly.
*
* @return void
*/
public function load_plugin_text_domain()
{
\load_plugin_textdomain($this->get_text_domain(), \false, $this->get_namespace() . '/lang/');
}
/**
* Append JS scripts in the WordPress admin panel. This is a hook function. Do not execute directly.
*
* @return void
*/
public function admin_enqueue_scripts()
{
}
/**
* Append JS scripts in WordPress. This is a hook function. Do not execute directly.
*
* @return void
*/
public function wp_enqueue_scripts()
{
}
/**
* Initialize plugin admin links. This is a hook function. Do not execute directly.
*
* @param string[] $links
*
* @return string[]
*/
public function links_filter($links)
{
$support_link = \get_locale() === 'pl_PL' ? 'https://www.wpdesk.pl/support/' : 'https://www.wpdesk.net/support';
if ($this->support_url) {
$support_link = $this->support_url;
}
$plugin_links = ['<a target="_blank" href="' . $support_link . '">' . \__('Support', $this->get_text_domain()) . '</a>'];
$links = \array_merge($plugin_links, $links);
if ($this->docs_url) {
$plugin_links = ['<a target="_blank" href="' . $this->docs_url . '">' . \__('Docs', $this->get_text_domain()) . '</a>'];
$links = \array_merge($plugin_links, $links);
}
if ($this->settings_url) {
$plugin_links = ['<a href="' . $this->settings_url . '">' . \__('Settings', $this->get_text_domain()) . '</a>'];
$links = \array_merge($plugin_links, $links);
}
return $links;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* Tag the plugin with this ingterface to hook it to the WordPress activation hook.
*
* Note: works from plugin flow ^2.2.
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Activateable
{
/**
* Plugin activated in WordPress. Do not execute directly.
*
* @return void
*/
public function activate();
}

View File

@@ -0,0 +1,24 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* It means that this class is should know about SUBSCRIPTION activation
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface ActivationAware
{
/**
* Set the activation flag to true
*
* @return void
*/
public function set_active();
/**
* Is subscription active?
*
* @return bool
*/
public function is_active();
}

View File

@@ -0,0 +1,70 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* @deprecated nobody uses it :) And also this library is not a place for this class
*
* @package WPDesk\PluginBuilder\Plugin
*/
class ActivationTracker
{
/**
* Namespace.
*
* @var string
*/
private $namespace;
/**
* ActivationTracker constructor.
*
* @param string $namespace Namespace for settings.
*/
public function __construct($namespace)
{
$this->namespace = $namespace;
}
/**
* Option name for date storage
*
* @return string
*/
private function get_option_name_activation_date()
{
return $this->namespace . '_activation';
}
/**
* Returns activation date and sets it if were not set before
*
* @return int unix timestamp for activation datetime
*/
public function get_activation_date()
{
$activation_date = \get_option($this->get_option_name_activation_date());
if (empty($activation_date)) {
return $this->touch_activation_date();
}
return \intval($activation_date);
}
/**
* Was activation more than two weeks before today
*
* @return bool
*/
public function is_activated_more_than_two_weeks()
{
$two_weeks = 60 * 60 * 24 * 7 * 2;
return $this->get_activation_date() + $two_weeks < \time();
}
/**
* Sets activatiion date for today
*
* @return int unit timestamp for now
*/
public function touch_activation_date()
{
$now = \time();
\update_option($this->get_option_name_activation_date(), $now);
return $now;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* Something that can be instantiated/hooked conditionally.
*
* @see https://github.com/mwpd/basic-scaffold/blob/master/src/Infrastructure/Conditional.php by Alain Schlesser
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Conditional
{
/**
* Check whether the conditional object is currently needed.
*
* @return bool Whether the conditional object is needed.
*/
public static function is_needed();
}

View File

@@ -0,0 +1,20 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* Tag the plugin with this ingterface to hook it to the WordPress deactivation hook.
*
* Note: works from plugin flow ^2.2.
*
* @package WPDesk\PluginBuilder\Plugin
*/
interface Deactivateable
{
/**
* Plugin deactivate in WordPress. Do not execute directly.
*
* @return void
*/
public function deactivate();
}

View File

@@ -0,0 +1,13 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
interface Hookable
{
/**
* Init hooks (actions and filters).
*
* @return void
*/
public function hooks();
}

View File

@@ -0,0 +1,21 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
interface HookableCollection extends \VendorDHL\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* Add hookable object.
*
* @param Hookable|HookablePluginDependant $hookable_object Hookable object.
*/
public function add_hookable(\VendorDHL\WPDesk\PluginBuilder\Plugin\Hookable $hookable_object);
/**
* Get hookable instance.
*
* @param string $class_name Class name.
*
* @return false|Hookable
*/
public function get_hookable_instance_by_class_name($class_name);
}

View File

@@ -0,0 +1,57 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
trait HookableParent
{
/**
* Hookable objects.
*
* @var array[Hookable]
*/
private $hookable_objects = array();
/**
* Add hookable object.
*
* @param Hookable|HookablePluginDependant $hookable_object Hookable object.
*/
public function add_hookable(\VendorDHL\WPDesk\PluginBuilder\Plugin\Hookable $hookable_object)
{
if ($hookable_object instanceof \VendorDHL\WPDesk\PluginBuilder\Plugin\HookablePluginDependant) {
$hookable_object->set_plugin($this);
}
$this->hookable_objects[] = $hookable_object;
}
/**
* Get hookable instance.
*
* @param string $class_name Class name.
*
* @return false|Hookable
*/
public function get_hookable_instance_by_class_name($class_name)
{
foreach ($this->hookable_objects as $hookable_object) {
if ($hookable_object instanceof $class_name) {
return $hookable_object;
}
}
return \false;
}
/**
* Run hooks method on all hookable objects.
*/
protected function hooks_on_hookable_objects()
{
/** @var Hookable $hookable_object $hookable_object */
foreach ($this->hookable_objects as $hookable_object) {
if ($hookable_object instanceof \VendorDHL\WPDesk\PluginBuilder\Plugin\Conditional) {
if ($hookable_object::is_needed()) {
$hookable_object->hooks();
}
} else {
$hookable_object->hooks();
}
}
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
interface HookablePluginDependant extends \VendorDHL\WPDesk\PluginBuilder\Plugin\Hookable
{
/**
* Set Plugin.
*
* @param AbstractPlugin $plugin Plugin.
*
* @return null
*/
public function set_plugin(\VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin $plugin);
/**
* Get plugin.
*
* @return AbstractPlugin.
*/
public function get_plugin();
}

View File

@@ -0,0 +1,34 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* @package WPDesk\PluginBuilder\Plugin
*/
trait PluginAccess
{
/**
* Plugin.
*
* @var AbstractPlugin
*/
private $plugin;
/**
* Set plugin.
*
* @param AbstractPlugin $plugin Plugin.
*/
public function set_plugin(\VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin $plugin)
{
$this->plugin = $plugin;
}
/**
* Get plugin.
*
* @return AbstractPlugin
*/
public function get_plugin()
{
return $this->plugin;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* Most clean plugin class with only most important details.
*/
abstract class SlimPlugin implements \VendorDHL\WPDesk_Translatable
{
/**
* Initializes plugin external state.
*
* The plugin internal state is initialized in the constructor and the plugin should be internally consistent after creation.
* The external state includes hooks execution, communication with other plugins, integration with WC etc.
*
* @return void
*/
public abstract function init();
}

View File

@@ -0,0 +1,63 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Plugin;
/**
* @deprecated Use wpdesk/wp-view
*
* @package WPDesk\PluginBuilder\Plugin
*/
trait TemplateLoad
{
/**
* Plugin path.
*
* @var string
*/
protected $plugin_path;
/**
* Template path.
*
* @var string
*/
protected $template_path;
/**
* Init base variables for plugin
*/
public function init_template_base_variables()
{
$this->plugin_path = $this->plugin_info->get_plugin_dir();
$this->template_path = $this->plugin_info->get_text_domain();
}
/**
* Renders end returns selected template
*
* @param string $name Name of the template.
* @param string $path Additional inner path to the template.
* @param array $args args Accessible from template.
*
* @return string
*/
public function load_template($name, $path = '', $args = array())
{
$plugin_template_path = \trailingslashit($this->plugin_path) . 'templates/';
// Look within passed path within the theme - this is priority.
$template = \locate_template(array(\trailingslashit($this->get_template_path()) . \trailingslashit($path) . $name . '.php'));
if (!$template) {
$template = $plugin_template_path . \trailingslashit($path) . $name . '.php';
}
\extract($args);
\ob_start();
include $template;
return \ob_get_clean();
}
/**
* Get template path.
*
* @return string
*/
public function get_template_path()
{
return \trailingslashit($this->template_path);
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace VendorDHL;
/**
* Have info about what class should be built by WPDesk_Builder
*
* have to be compatible with PHP 5.2.x
*/
interface WPDesk_Buildable
{
/** @return string */
public function get_class_name();
}

View File

@@ -0,0 +1,27 @@
<?php
namespace VendorDHL;
if (!\interface_exists('VendorDHL\\WPDesk_Translatable')) {
require_once __DIR__ . '/Translatable.php';
}
/**
* Have MUST HAVE info for plugin instantion
*
* have to be compatible with PHP 5.2.x
*/
interface WPDesk_Has_Plugin_Info extends \VendorDHL\WPDesk_Translatable
{
/**
* @return string
*/
public function get_plugin_file_name();
/**
* @return string
*/
public function get_plugin_dir();
/**
* @return string
*/
public function get_version();
}

View File

@@ -0,0 +1,190 @@
<?php
namespace VendorDHL;
if (!\interface_exists('VendorDHL\\WPDesk_Translatable')) {
require_once __DIR__ . '/Translatable.php';
}
if (!\interface_exists('VendorDHL\\WPDesk_Buildable')) {
require_once __DIR__ . '/Buildable.php';
}
if (!\interface_exists('VendorDHL\\WPDesk_Has_Plugin_Info')) {
require_once __DIR__ . '/Has_Plugin_Info.php';
}
/**
* Structure with core info about plugin
*
* have to be compatible with PHP 5.2.x
*/
class WPDesk_Plugin_Info implements \VendorDHL\WPDesk_Translatable, \VendorDHL\WPDesk_Buildable, \VendorDHL\WPDesk_Has_Plugin_Info
{
/** @var string */
private $plugin_file_name;
/** @var string */
private $plugin_dir;
/** @var string */
private $plugin_url;
/** @var string */
private $class_name;
/** @var string */
private $version;
/** @var string */
private $product_id;
/** @var string */
private $plugin_name;
/** @var \DateTimeInterface */
private $release_date;
/** string */
private $text_domain;
/**
* @var array
*/
private $plugin_shops;
/**
* @return string
*/
public function get_plugin_file_name()
{
return $this->plugin_file_name;
}
/**
* @param string $plugin_name
*/
public function set_plugin_file_name($plugin_name)
{
$this->plugin_file_name = $plugin_name;
}
/**
* @return string
*/
public function get_plugin_dir()
{
return $this->plugin_dir;
}
/**
* @param string $plugin_dir
*/
public function set_plugin_dir($plugin_dir)
{
$this->plugin_dir = $plugin_dir;
}
/**
* @return string
*/
public function get_plugin_url()
{
return $this->plugin_url;
}
/**
* @param string $plugin_url
*/
public function set_plugin_url($plugin_url)
{
$this->plugin_url = $plugin_url;
}
/**
* @return string
*/
public function get_version()
{
return $this->version;
}
/**
* @param string $version
*/
public function set_version($version)
{
$this->version = $version;
}
/**
* @return string
*/
public function get_product_id()
{
return $this->product_id;
}
/**
* @param string $product_id
*/
public function set_product_id($product_id)
{
$this->product_id = $product_id;
}
/**
* @return string
*/
public function get_plugin_name()
{
return $this->plugin_name;
}
/**
* @param string $plugin_name
*/
public function set_plugin_name($plugin_name)
{
$this->plugin_name = $plugin_name;
}
/**
* @return DateTimeInterface
*/
public function get_release_date()
{
return $this->release_date;
}
/**
* @param \DateTimeInterface $release_date
*/
public function set_release_date($release_date)
{
$this->release_date = $release_date;
}
/**
* @return string
*/
public function get_class_name()
{
return $this->class_name;
}
/**
* @param string $class_name
*/
public function set_class_name($class_name)
{
$this->class_name = $class_name;
}
/**
* @return string
*/
public function get_text_domain()
{
return $this->text_domain;
}
/**
* @param $value
*/
public function set_text_domain($value)
{
$this->text_domain = $value;
}
/**
* @return array
*/
public function get_plugin_shops()
{
return $this->plugin_shops;
}
/**
* @param array $plugin_shops
*/
public function set_plugin_shops($plugin_shops)
{
$this->plugin_shops = $plugin_shops;
}
/**
* @return string
*/
public function get_plugin_slug()
{
return \basename($this->get_plugin_dir());
}
}

View File

@@ -0,0 +1,12 @@
<?php
namespace VendorDHL;
/**
* @deprecated Have typo so better use WPDesk_Translatable
*/
interface WPDesk_Translable
{
/** @return string */
public function get_text_domain();
}

View File

@@ -0,0 +1,17 @@
<?php
namespace VendorDHL;
if (!\interface_exists('VendorDHL\\WPDesk_Translable')) {
require_once 'Translable.php';
}
/**
* Have info about textdomain - how to translate texts
*
* have to be compatible with PHP 5.2.x
*/
interface WPDesk_Translatable extends \VendorDHL\WPDesk_Translable
{
/** @return string */
public function get_text_domain();
}

View File

@@ -0,0 +1,7 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage\Exception;
class ClassAlreadyExists extends \RuntimeException
{
}

View File

@@ -0,0 +1,7 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage\Exception;
class ClassNotExists extends \RuntimeException
{
}

View File

@@ -0,0 +1,19 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
interface PluginStorage
{
/**
* @param string $class
* @param AbstractPlugin $object
*/
public function add_to_storage($class, $object);
/**
* @param string $class
*
* @return AbstractPlugin
*/
public function get_from_storage($class);
}

View File

@@ -0,0 +1,37 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
/**
* Can store plugin instances in static variable
*
* @package WPDesk\PluginBuilder\Storage
*/
class StaticStorage implements \VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage
{
protected static $instances = [];
/**
* @param string $class
* @param AbstractPlugin $object
*/
public function add_to_storage($class, $object)
{
if (isset(self::$instances[$class])) {
throw new \VendorDHL\WPDesk\PluginBuilder\Storage\Exception\ClassAlreadyExists("Class {$class} already exists");
}
self::$instances[$class] = $object;
}
/**
* @param string $class
*
* @return AbstractPlugin
*/
public function get_from_storage($class)
{
if (isset(self::$instances[$class])) {
return self::$instances[$class];
}
throw new \VendorDHL\WPDesk\PluginBuilder\Storage\Exception\ClassNotExists("Class {$class} not exists in storage");
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage;
class StorageFactory
{
/**
* @return PluginStorage
*/
public function create_storage()
{
return new \VendorDHL\WPDesk\PluginBuilder\Storage\WordpressFilterStorage();
}
}

View File

@@ -0,0 +1,41 @@
<?php
namespace VendorDHL\WPDesk\PluginBuilder\Storage;
use VendorDHL\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
/**
* Can store plugin instances in WordPress filter system.
*
* @package WPDesk\PluginBuilder\Storage
*/
class WordpressFilterStorage implements \VendorDHL\WPDesk\PluginBuilder\Storage\PluginStorage
{
const STORAGE_FILTER_NAME = 'wpdesk_plugin_instances';
/**
* @param string $class
* @param AbstractPlugin $object
*/
public function add_to_storage($class, $object)
{
\add_filter(self::STORAGE_FILTER_NAME, static function ($plugins) use($class, $object) {
if (isset($plugins[$class])) {
throw new \VendorDHL\WPDesk\PluginBuilder\Storage\Exception\ClassAlreadyExists("Class {$class} already exists");
}
$plugins[$class] = $object;
return $plugins;
});
}
/**
* @param string $class
*
* @return AbstractPlugin
*/
public function get_from_storage($class)
{
$plugins = \apply_filters(self::STORAGE_FILTER_NAME, []);
if (isset($plugins[$class])) {
return $plugins[$class];
}
throw new \VendorDHL\WPDesk\PluginBuilder\Storage\Exception\ClassNotExists("Class {$class} not exists in storage");
}
}

View File

@@ -0,0 +1,38 @@
{
"name": "wpdesk\/wp-code-sniffer",
"description": "Library for WP Desk Coding standards in plugins.",
"license": "MIT",
"keywords": [
"wordpress",
"code sniffer",
"admin"
],
"homepage": "https:\/\/gitlab.com\/wpdesk\/wp-code-sniffer",
"type": "phpcodesniffer-standard",
"minimum-stability": "stable",
"authors": [
{
"name": "grola",
"email": "grola@wpdesk.net"
}
],
"require": {
"dealerdirect\/phpcodesniffer-composer-installer": "^0.6.2",
"phpcompatibility\/php-compatibility": "^9.3",
"squizlabs\/php_codesniffer": "^3.5",
"wp-coding-standards\/wpcs": "^2.2"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"mockery\/mockery": "*",
"10up\/wp_mock": "*"
},
"autoload": {},
"autoload-dev": {},
"scripts": {
"phpcs": "phpcs"
},
"extra": {
"class": "WPDesk\\Composer\\Codeception\\Plugin"
}
}

View File

@@ -0,0 +1,57 @@
{
"name": "wpdesk\/wp-codeception",
"description": "Library for WP Desk Codeception tests.",
"license": "MIT",
"keywords": [
"wordpress",
"codeception",
"admin"
],
"homepage": "https:\/\/gitlab.com\/wpdesk\/wp-codeception",
"type": "composer-plugin",
"minimum-stability": "stable",
"authors": [
{
"name": "grola",
"email": "grola@wpdesk.net"
}
],
"require": {
"php": ">=5.6",
"ext-json": "*",
"wpdesk\/wp-builder": "^1.0",
"composer-plugin-api": "^1.1",
"codeception\/module-db": "^1.0",
"codeception\/module-cli": "^1.0",
"codeception\/module-webdriver": "^1.0",
"lucatume\/wp-browser": "^2.4",
"codeception\/module-filesystem": "^1.0",
"codeception\/module-rest": "^1.2",
"codeception\/module-phpbrowser": "^1.0",
"codeception\/module-asserts": "^1.1",
"codeception\/util-universalframework": "^1.0",
"vlucas\/phpdotenv": "^4.1"
},
"require-dev": {
"phpunit\/phpunit": "<7",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"mockery\/mockery": "*",
"10up\/wp_mock": "*",
"wimg\/php-compatibility": "^8"
},
"autoload": {
"psr-4": {
"VendorDHL\\WPDesk\\Codeception\\": "src\/WPDesk\/Codeception",
"VendorDHL\\Codeception\\Module\\": "src\/Codeception\/Module",
"VendorDHL\\WPDesk\\Composer\\Codeception\\": "src\/WPDesk\/Composer"
}
},
"autoload-dev": {},
"scripts": {
"phpcs": "phpcs"
},
"extra": {
"class": "WPDesk\\Composer\\Codeception\\Plugin"
}
}

View File

@@ -0,0 +1,63 @@
<?php
namespace VendorDHL\WPDesk\Codeception\Command;
use VendorDHL\Codeception\Lib\Generator\Test;
/**
* Class code for codeception example test for WP Desk plugin activation.
*
* @package WPDesk\Codeception\Command
*/
class AcceptanceTestGenerator extends \VendorDHL\Codeception\Lib\Generator\Test
{
protected $template = <<<EOF
<?php {{namespace}}
use WPDesk\\Codeception\\Tests\\Acceptance\\Cest\\AbstractCestForPluginActivation;
class {{name}} extends AbstractCestForPluginActivation {
\t/**
\t * Deactivate plugins before tests.
\t *
\t * @param AcceptanceTester \$i .
\t *
\t * @throws \\Codeception\\Exception\\ModuleException .
\t */
\tpublic function _before( \$i ) {
\t\t\$i->loginAsAdministrator();
\t\t\$i->amOnPluginsPage();
\t\t\$i->deactivatePlugin( \$this->getPluginSlug() );
\t\t\$i->amOnPluginsPage();
\t\t\$i->seePluginDeactivated( \$this->getPluginSlug() );
\t\t\$i->amOnPluginsPage();
\t\t\$i->deactivatePlugin( self::WOOCOMMERCE_PLUGIN_SLUG );
\t\t\$i->amOnPluginsPage();
\t\t\$i->seePluginDeactivated( self::WOOCOMMERCE_PLUGIN_SLUG );
\t}
\t/**
\t * Plugin activation.
\t *
\t * @param AcceptanceTester \$i .
\t *
\t * @throws \\Codeception\\Exception\\ModuleException .
\t */
\tpublic function pluginActivation( \$i ) {
\t\t\$i->loginAsAdministrator();
\t\t\$i->amOnPluginsPage();
\t\t\$i->seePluginDeactivated( \$this->getPluginSlug() );
\t\t// This is an example and you should change it to current plugin.
\t\t\$i->activateWPDeskPlugin(
\t\t\t\$this->getPluginSlug(),
\t\t\tarray( 'woocommerce' ),
\t\t\tarray( 'The “WooCommerce Fakturownia” plugin cannot run without WooCommerce active. Please install and activate WooCommerce plugin.' )
\t\t);
\t}
}
EOF;
}

View File

@@ -0,0 +1,70 @@
<?php
namespace VendorDHL\WPDesk\Codeception\Command;
use VendorDHL\Codeception\Command\GenerateTest;
use VendorDHL\Codeception\CustomCommandInterface;
use VendorDHL\Symfony\Component\Console\Input\InputInterface;
use VendorDHL\Symfony\Component\Console\Output\OutputInterface;
/**
* Generates codeception example test for WP Desk plugin activation.
*
* @package WPDesk\Codeception\Command
*/
class GeneratePluginActivation extends \VendorDHL\Codeception\Command\GenerateTest implements \VendorDHL\Codeception\CustomCommandInterface
{
/**
* Get codeception command description.
*
* @return string
*/
public function getDescription()
{
return 'Generates plugin activation tests.';
}
/**
* Returns the name of the command.
*
* @return string
*/
public static function getCommandName()
{
return 'generate:activation';
}
/**
* Get generator class.
*
* @param array $config .
* @param string $class .
* @return AcceptanceTestGenerator
*/
protected function getGenerator($config, $class)
{
return new \VendorDHL\WPDesk\Codeception\Command\AcceptanceTestGenerator($config, $class);
}
/**
* Execute command.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return void
*/
public function execute(\VendorDHL\Symfony\Component\Console\Input\InputInterface $input, \VendorDHL\Symfony\Component\Console\Output\OutputInterface $output)
{
$suite = $input->getArgument('suite');
$class = $input->getArgument('class');
$config = $this->getSuiteConfig($suite);
$className = $this->getShortClassName($class);
$path = $this->createDirectoryFor($config['path'], $class);
$filename = $this->completeSuffix($className, 'Cest');
$filename = $path . $filename;
$gen = $this->getGenerator($config, $class);
$res = $this->createFile($filename, $gen->produce());
if (!$res) {
$output->writeln("<error>Test {$filename} already exists</error>");
return;
}
$output->writeln("<info>Test was created in {$filename}</info>");
}
}

View File

@@ -0,0 +1,70 @@
<?php
namespace VendorDHL\WPDesk\Codeception\Command;
use VendorDHL\Codeception\Command\GenerateTest;
use VendorDHL\Codeception\CustomCommandInterface;
use VendorDHL\Symfony\Component\Console\Input\InputInterface;
use VendorDHL\Symfony\Component\Console\Output\OutputInterface;
/**
* Generates codeception example test for WP Desk plugin activation.
*
* @package WPDesk\Codeception\Command
*/
class GenerateWooCommerce extends \VendorDHL\Codeception\Command\GenerateTest implements \VendorDHL\Codeception\CustomCommandInterface
{
/**
* Get codeception command description.
*
* @return string
*/
public function getDescription()
{
return 'Generates woocommerce tests.';
}
/**
* Returns the name of the command.
*
* @return string
*/
public static function getCommandName()
{
return 'generate:woocommerce';
}
/**
* Get generator class.
*
* @param array $config .
* @param string $class .
* @return WooCommerceTestGenerator
*/
protected function getGenerator($config, $class)
{
return new \VendorDHL\WPDesk\Codeception\Command\WooCommerceTestGenerator($config, $class);
}
/**
* Execute command.
*
* @param InputInterface $input
* @param OutputInterface $output
*
* @return void
*/
public function execute(\VendorDHL\Symfony\Component\Console\Input\InputInterface $input, \VendorDHL\Symfony\Component\Console\Output\OutputInterface $output)
{
$suite = $input->getArgument('suite');
$class = $input->getArgument('class');
$config = $this->getSuiteConfig($suite);
$className = $this->getShortClassName($class);
$path = $this->createDirectoryFor($config['path'], $class);
$filename = $this->completeSuffix($className, 'Cest');
$filename = $path . $filename;
$gen = $this->getGenerator($config, $class);
$res = $this->createFile($filename, $gen->produce());
if (!$res) {
$output->writeln("<error>Test {$filename} already exists</error>");
return;
}
$output->writeln("<info>Test was created in {$filename}</info>");
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace VendorDHL\WPDesk\Codeception\Command;
use VendorDHL\Codeception\Lib\Generator\Test;
/**
* Class code for codeception example test for WP Desk plugin activation.
*
* @package WPDesk\Codeception\Command
*/
class WooCommerceTestGenerator extends \VendorDHL\Codeception\Lib\Generator\Test
{
protected $template = <<<EOF
<?php {{namespace}}
use WPDesk\\Codeception\\Tests\\Acceptance\\Cest\\AbstractCestForWooCommerce;
/**
* Common WooCommerce tests.
*/
class {{name}} extends AbstractCestForWooCommerce {
}
EOF;
}

View File

@@ -0,0 +1,16 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception;
use VendorDHL\WPDesk\Composer\Codeception\Commands\CreateCodeceptionTests;
use VendorDHL\WPDesk\Composer\Codeception\Commands\RunCodeceptionTests;
/**
* Links plugin commands handlers to composer.
*/
class CommandProvider implements \VendorDHL\Composer\Plugin\Capability\CommandProvider
{
public function getCommands()
{
return [new \VendorDHL\WPDesk\Composer\Codeception\Commands\CreateCodeceptionTests(), new \VendorDHL\WPDesk\Composer\Codeception\Commands\RunCodeceptionTests()];
}
}

View File

@@ -0,0 +1,22 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception\Commands;
use VendorDHL\Composer\Command\BaseCommand as CodeceptionBaseCommand;
use VendorDHL\Symfony\Component\Console\Output\OutputInterface;
/**
* Base for commands - declares common methods.
*
* @package WPDesk\Composer\Codeception\Commands
*/
abstract class BaseCommand extends \VendorDHL\Composer\Command\BaseCommand
{
/**
* @param string $command
* @param OutputInterface $output
*/
protected function execAndOutput($command, \VendorDHL\Symfony\Component\Console\Output\OutputInterface $output)
{
\passthru($command);
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception\Commands;
use VendorDHL\Composer\Downloader\FilesystemException;
use VendorDHL\Symfony\Component\Console\Input\InputInterface;
use VendorDHL\Symfony\Component\Console\Output\OutputInterface;
/**
* Codeception tests creator command.
*
* @package WPDesk\Composer\Codeception\Commands
*/
class CreateCodeceptionTests extends \VendorDHL\WPDesk\Composer\Codeception\Commands\BaseCommand
{
use SedTrait;
/**
* Configure command.
*/
protected function configure()
{
parent::configure();
$this->setName('create-codeception-tests')->setDescription('Create codeception tests directories and files.');
}
/**
* Copy file.
*
* @param string $source
* @param string $dest
* @param string $exceptionMessage
* @throws FilesystemException
*/
private function copy($source, $dest, $exceptionMessage)
{
if (!\copy($source, $dest)) {
throw new \VendorDHL\Composer\Downloader\FilesystemException($exceptionMessage);
}
}
/**
* Copy configuration files.
*
* @param $codeceptionDir
* @param $testsDir
* @param $codeceptionYml
* @param $envConfig
* @param $acceptanceYml
* @param $bootstrapScript
* @return void
* @throws FilesystemException
*/
private function copyConfigurationFiles($codeceptionDir, $testsDir, $codeceptionYml, $envConfig, $acceptanceYml, $bootstrapScript)
{
if (!\file_exists('./' . $codeceptionYml)) {
$this->copy('./vendor/wpdesk/wp-codeception/configuration/' . $codeceptionYml, './' . $codeceptionYml, 'Error copying codeception configuration file!');
}
if (!\file_exists('./' . $envConfig)) {
$this->copy('./vendor/wpdesk/wp-codeception/configuration/' . $envConfig, './' . $envConfig, 'Error copying codeception env configuration file!');
}
if (\file_exists($testsDir . '/' . $acceptanceYml)) {
\unlink($testsDir . '/' . $acceptanceYml);
}
$this->copy('./vendor/wpdesk/wp-codeception/configuration/' . $acceptanceYml, $testsDir . '/' . $acceptanceYml, 'Error copying codeception acceptance configuration file!');
if (!\file_exists($codeceptionDir . '/' . $bootstrapScript)) {
$this->copy('./vendor/wpdesk/wp-codeception/scripts/' . $bootstrapScript, $codeceptionDir . '/' . $bootstrapScript, 'Error copying codeception bootstrap script file!');
}
if (!@\file_exists($testsDir . '/_output')) {
\mkdir($testsDir . '/_output', 0777, \true);
}
if (!\file_exists($testsDir . '/_output/.gitignore')) {
$this->copy('./vendor/wpdesk/wp-codeception/configuration/_output.gitignore', $testsDir . '/_output/.gitignore', 'Error copying codeception acceptance output .gitignore file!');
}
if (!@\file_exists($testsDir . '/_support/_generated')) {
\mkdir($testsDir . '/_support/_generated', 0777, \true);
}
if (!\file_exists($testsDir . '/_support/_generated/.gitignore')) {
$this->copy('./vendor/wpdesk/wp-codeception/configuration/_generated.gitignore', $testsDir . '/_support/_generated/.gitignore', 'Error copying codeception acceptance output .gitignore file!');
}
}
/**
* Inject traits into tester class.
*
* @param string $testsDir
* @return void
*/
private function injectTraitsIntoTesterClass($testsDir)
{
$file_pattern = $testsDir . '/_support/AcceptanceTester.php';
$pattern = "/use _generated\\\\AcceptanceTesterActions;/";
$replace = "use _generated\\AcceptanceTesterActions;\n" . "\n\tuse \\WPDesk\\Codeception\\Tests\\Acceptance\\Tester\\TesterWordpressActions;" . "\n\tuse \\WPDesk\\Codeception\\Tests\\Acceptance\\Tester\\TesterWooCommerceActions;" . "\n\tuse \\WPDesk\\Codeception\\Tests\\Acceptance\\Tester\\TesterWPDeskActions;";
$this->wpdeskSed($file_pattern, $pattern, $replace);
}
/**
* Execute command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return void
* @throws FilesystemException
*/
protected function execute(\VendorDHL\Symfony\Component\Console\Input\InputInterface $input, \VendorDHL\Symfony\Component\Console\Output\OutputInterface $output)
{
$codeceptionDir = './tests/codeception';
$testsDir = $codeceptionDir . '/tests';
$codeceptionYml = 'codeception.dist.yml';
$envConfig = '.env.testing';
$acceptanceYml = 'acceptance.suite.yml';
$bootstrapScript = 'bootstrap.sh';
if (!@\file_exists($testsDir)) {
\mkdir($testsDir, 0777, \true);
}
$this->copyConfigurationFiles($codeceptionDir, $testsDir, $codeceptionYml, $envConfig, $acceptanceYml, $bootstrapScript);
$this->execAndOutput('./vendor/bin/codecept bootstrap ' . $codeceptionDir, $output);
$this->execAndOutput('./vendor/bin/codecept generate:activation acceptance ActivationCest', $output);
$this->execAndOutput('./vendor/bin/codecept generate:woocommerce acceptance WooCommerceCest', $output);
$this->injectTraitsIntoTesterClass($testsDir);
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception\Commands;
use VendorDHL\Symfony\Component\Console\Input\InputArgument;
use VendorDHL\Symfony\Component\Console\Input\InputInterface;
use VendorDHL\Symfony\Component\Console\Output\OutputInterface;
/**
* Codeception tests run command.
*
* @package WPDesk\Composer\Codeception\Commands
*/
class RunCodeceptionTests extends \VendorDHL\WPDesk\Composer\Codeception\Commands\BaseCommand
{
const SINGLE = 'single';
const FAST = 'fast';
const WOOCOMMERCE_VERSION = 'woo_version';
/**
* Configure command.
*/
protected function configure()
{
parent::configure();
$this->setName('run-codeception-tests')->setDescription('Run codeception tests.')->setDefinition(array(new \VendorDHL\Symfony\Component\Console\Input\InputArgument(self::SINGLE, \VendorDHL\Symfony\Component\Console\Input\InputArgument::OPTIONAL, 'Name of Single test to run.', 'all'), new \VendorDHL\Symfony\Component\Console\Input\InputArgument(self::FAST, \VendorDHL\Symfony\Component\Console\Input\InputArgument::OPTIONAL, 'Fast tests - do not shutdown docker-compose.', 'slow'), new \VendorDHL\Symfony\Component\Console\Input\InputArgument(self::WOOCOMMERCE_VERSION, \VendorDHL\Symfony\Component\Console\Input\InputArgument::OPTIONAL, 'WooCommerce version to install.', '')));
}
/**
* Execute command.
*
* @param InputInterface $input
* @param OutputInterface $output
* @return void
*/
protected function execute(\VendorDHL\Symfony\Component\Console\Input\InputInterface $input, \VendorDHL\Symfony\Component\Console\Output\OutputInterface $output)
{
$dockerComposeYaml = 'vendor/wpdesk/wp-codeception/docker/docker-compose.yaml';
$singleTest = $input->getArgument(self::SINGLE);
$fastTest = $input->getArgument(self::FAST);
$wooVersion = $input->getArgument(self::WOOCOMMERCE_VERSION);
$cache_dir = \sys_get_temp_dir() . '/codeception_cache';
if (!\file_exists($cache_dir)) {
\mkdir($cache_dir, 0777, \true);
}
\putenv('TMP_CACHE_DIR=' . $cache_dir);
$codecept_param = ' --html --verbose -f ';
$additionalParameters = ' -e CODECEPT_PARAM="' . $codecept_param . '" ';
if (!empty($singleTest) && 'all' !== $singleTest) {
$additionalParameters .= ' -e CODECEPT_PARAM="' . $codecept_param . ' acceptance ' . $singleTest . '" ';
}
if (!empty($wooVersion)) {
$additionalParameters .= ' -e WOOCOMMERCE_VERSION="' . $wooVersion . '" ';
}
$runTestsCommand = 'docker-compose -f ' . $dockerComposeYaml . ' run ' . $additionalParameters . 'codecept';
$output->writeln('Codeception command: ' . $runTestsCommand);
$this->execAndOutput($runTestsCommand, $output);
if (empty($fastTest) || self::FAST !== $fastTest) {
$this->execAndOutput('docker-compose -f ' . $dockerComposeYaml . ' down -v', $output);
}
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception\Commands;
/**
* Trait with a sed like command
* @see https://pl.wikipedia.org/wiki/Sed_(program)
*
* @package WPDesk\Composer\GitPlugin\Command
*/
trait SedTrait
{
/**
* SED.
*
* @param string $file_pattern .
* @param string $pattern .
* @param string $replace .
*
* @return string[] array of changed files
*/
private function wpdeskSed($file_pattern, $pattern, $replace)
{
$changed_files = [];
foreach (\glob($file_pattern) as $filename) {
$input = \file_get_contents($filename);
$output = \preg_replace($pattern, $replace, $input);
if ($output !== $input) {
$changed_files[] = $filename;
\file_put_contents($filename, $output);
}
}
return $changed_files;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace VendorDHL\WPDesk\Composer\Codeception;
use VendorDHL\Composer\Composer;
use VendorDHL\Composer\IO\IOInterface;
use VendorDHL\Composer\Plugin\Capable;
use VendorDHL\Composer\Plugin\PluginInterface;
/**
* Composer plugin.
*
* @package WPDesk\Composer\Codeception
*/
class Plugin implements \VendorDHL\Composer\Plugin\PluginInterface, \VendorDHL\Composer\Plugin\Capable
{
/**
* @var Composer
*/
private $composer;
/**
* @var IOInterface
*/
private $io;
public function activate(\VendorDHL\Composer\Composer $composer, \VendorDHL\Composer\IO\IOInterface $io)
{
$this->composer = $composer;
$this->io = $io;
}
public function getCapabilities()
{
return [\VendorDHL\Composer\Plugin\Capability\CommandProvider::class => \VendorDHL\WPDesk\Composer\Codeception\CommandProvider::class];
}
}

View File

@@ -0,0 +1,51 @@
{
"name": "wpdesk\/wp-logs",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"config": {
"platform": {
"php": "7.0.19"
},
"allow-plugins": {
"dealerdirect\/phpcodesniffer-composer-installer": true
}
},
"require": {
"php": ">=7.0|^8",
"psr\/log": "^1",
"monolog\/monolog": "^1.23",
"wpdesk\/wp-notice": "^3.0"
},
"require-dev": {
"phpunit\/phpunit": "^5",
"squizlabs\/php_codesniffer": "^3.0.2",
"wpdesk\/wp-code-sniffer": "^1.2.3"
},
"autoload": {
"psr-4": {
"VendorDHL\\WPDesk\\Logger\\": "src\/"
}
},
"scripts": {
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
},
"extra": {
"text-domain": "wp-logs",
"translations-folder": "lang",
"po-files": {
"pl_PL": "pl_PL.po",
"en_AU": "en_AU.po",
"en_CA": "en_CA.po",
"en_GB": "en_GB.po",
"es_ES": "es_ES.po",
"de_DE": "de_DE.po"
}
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace VendorDHL\WPDesk\Logger;
use VendorDHL\Monolog\Handler\HandlerInterface;
use VendorDHL\Monolog\Logger;
use VendorDHL\Monolog\Registry;
/**
* Manages and facilitates creation of logger
*
* @package WPDesk\Logger
*/
class BasicLoggerFactory implements \VendorDHL\WPDesk\Logger\LoggerFactory
{
/** @var string Last created logger name/channel */
private static $lastLoggerChannel;
/**
* Creates logger for plugin
*
* @param string $name The logging channel/name of logger
* @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
* @param callable[] $processors Optional array of processors
* @return Logger
*/
public function createLogger($name, $handlers = array(), array $processors = array())
{
if (\VendorDHL\Monolog\Registry::hasLogger($name)) {
return \VendorDHL\Monolog\Registry::getInstance($name);
}
self::$lastLoggerChannel = $name;
$logger = new \VendorDHL\Monolog\Logger($name, $handlers, $processors);
\VendorDHL\Monolog\Registry::addLogger($logger);
return $logger;
}
/**
* Returns created Logger by name or last created logger
*
* @param string $name Name of the logger
*
* @return Logger
*/
public function getLogger($name = null)
{
if ($name === null) {
$name = self::$lastLoggerChannel;
}
return \VendorDHL\Monolog\Registry::getInstance($name);
}
}

View File

@@ -0,0 +1,114 @@
<?php
namespace VendorDHL\WPDesk\Logger;
use VendorDHL\Monolog\Logger;
use VendorDHL\Psr\Log\LogLevel;
use WP_Error;
use Exception;
/**
* Facilitates creation of logger with default WPDesk settings
*
* @deprecated Only for backward compatibility. Please use injected Logger compatible with PSR
*
* @package WPDesk\Logger
*/
class LoggerFacade
{
const BACKTRACE_FILENAME_KEY = 'file';
/** @var WPDeskLoggerFactory */
private static $factory;
/**
* Get logger by name. If not exists create one.
*
* @param string $name Name of the logger
* @return Logger
*/
public static function getLogger($name = \VendorDHL\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
{
if (self::$factory === null) {
self::$factory = new \VendorDHL\WPDesk\Logger\WPDeskLoggerFactory();
}
return self::$factory->createWPDeskLogger($name);
}
/**
* Snake case alias for getLogger
*
* @param string $name
*
* @return Logger
*/
public static function get_logger($name = \VendorDHL\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
{
return self::getLogger($name);
}
/**
* If set, logs are disabled
*
* @param string $name Name of the logger
*/
public static function set_disable_log($name = \VendorDHL\WPDesk\Logger\WPDeskLoggerFactory::DEFAULT_LOGGER_CHANNEL_NAME)
{
self::$factory->disableLog($name);
}
/**
* Log this exception into WPDesk logger
*
* @param WP_Error $e Error to log.
* @param array $backtrace Backtrace information with snapshot of error env.
* @param array $context Context to log
* @param string $level Level of error.
*
* @see http://php.net/manual/en/function.debug-backtrace.php
*/
public static function log_wp_error(\WP_Error $e, array $backtrace, array $context = array(), $level = \VendorDHL\Psr\Log\LogLevel::ERROR)
{
$message = 'Error: ' . \get_class($e) . ' Code: ' . $e->get_error_code() . ' Message: ' . $e->get_error_message();
self::log_message_backtrace($message, $backtrace, $context, $level);
}
/**
* Log this exception into WPDesk logger
*
* @param Exception $e Exception to log.
* @param array $context Context to log
* @param string $level Level of error.
*/
public static function log_exception(\Exception $e, array $context = array(), $level = \VendorDHL\Psr\Log\LogLevel::ERROR)
{
$message = 'Exception: ' . \get_class($e) . ' Code: ' . $e->getCode() . ' Message: ' . $e->getMessage() . ' Stack: ' . $e->getTraceAsString();
self::log_message($message, \array_merge($context, ['exception' => $e]), $e->getFile(), $level);
}
/**
* Log message into WPDesk logger
*
* @param string $message Message to log.
* @param array $context Context to log
* @param string $source Source of the message - can be file name, class name or whatever.
* @param string $level Level of error.
*/
public static function log_message($message, array $context = array(), $source = null, $level = \VendorDHL\Psr\Log\LogLevel::DEBUG)
{
$logger = self::getLogger();
if ($source !== null) {
$context = \array_merge($context, ['source' => $source]);
}
$logger->log($level, $message, $context);
}
/**
* Log message into WPDesk logger
*
* @param string $message Message to log.
* @param array $backtrace Backtrace information with snapshot of error env.
* @param array $context Context to log
* @param string $level Level of error.
*/
public static function log_message_backtrace($message, array $backtrace, array $context = array(), $level = \VendorDHL\Psr\Log\LogLevel::DEBUG)
{
$message .= ' Backtrace: ' . \json_encode($backtrace);
$source = null;
if (isset($backtrace[self::BACKTRACE_FILENAME_KEY])) {
$source = $backtrace[self::BACKTRACE_FILENAME_KEY];
}
self::log_message($message, $context, $source, $level);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace VendorDHL\WPDesk\Logger;
use VendorDHL\Monolog\Logger;
/*
* @package WPDesk\Logger
*/
interface LoggerFactory
{
/**
* Returns created Logger
*
* @param string $name
*
* @return Logger
*/
public function getLogger($name);
}

View File

@@ -0,0 +1,25 @@
<?php
namespace VendorDHL\WPDesk\Logger;
use VendorDHL\Psr\Log\LogLevel;
final class Settings
{
/** @var string */
public $level = \VendorDHL\Psr\Log\LogLevel::DEBUG;
/** @var bool */
public $use_wc_log = \true;
/** @var bool */
public $use_wp_log = \true;
/**
* @param string $level
* @param bool $use_wc_log
* @param bool $use_wp_log
*/
public function __construct(string $level = \VendorDHL\Psr\Log\LogLevel::DEBUG, bool $use_wc_log = \true, bool $use_wp_log = \true)
{
$this->level = $level;
$this->use_wc_log = $use_wc_log;
$this->use_wp_log = $use_wp_log;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare (strict_types=1);
namespace VendorDHL\WPDesk\Logger;
use VendorDHL\Monolog\Handler\HandlerInterface;
use VendorDHL\Monolog\Handler\NullHandler;
use VendorDHL\Monolog\Logger;
use VendorDHL\Monolog\Handler\ErrorLogHandler;
use VendorDHL\WPDesk\Logger\WC\WooCommerceHandler;
final class SimpleLoggerFactory implements \VendorDHL\WPDesk\Logger\LoggerFactory
{
/** @var Settings */
private $options;
/** @var string */
private $channel;
/** @var Logger */
private $logger;
public function __construct(string $channel, \VendorDHL\WPDesk\Logger\Settings $options = null)
{
$this->channel = $channel;
$this->options = $options ?? new \VendorDHL\WPDesk\Logger\Settings();
}
public function getLogger($name = null) : \VendorDHL\Monolog\Logger
{
if ($this->logger) {
return $this->logger;
}
$this->logger = new \VendorDHL\Monolog\Logger($this->channel);
if ($this->options->use_wc_log) {
if (\function_exists('wc_get_logger')) {
$this->create_wc_handler();
} else {
\add_action('woocommerce_init', [$this, 'create_wc_handler']);
}
}
// Adding WooCommerce logger may have failed, if so add WP by default.
if ($this->options->use_wp_log || empty($this->logger->getHandlers())) {
$this->logger->pushHandler($this->get_wp_handler());
}
return $this->logger;
}
/**
* @internal
*/
public function create_wc_handler()
{
while (!$this->options->use_wp_log && !empty($this->logger->getHandlers())) {
$this->logger->popHandler();
}
$this->logger->pushHandler(new \VendorDHL\WPDesk\Logger\WC\WooCommerceHandler(\wc_get_logger(), $this->channel));
}
private function get_wp_handler() : \VendorDHL\Monolog\Handler\HandlerInterface
{
if (\defined('VendorDHL\\WP_DEBUG_LOG') && WP_DEBUG_LOG) {
return new \VendorDHL\Monolog\Handler\ErrorLogHandler(\VendorDHL\Monolog\Handler\ErrorLogHandler::OPERATING_SYSTEM, $this->options->level);
}
return new \VendorDHL\Monolog\Handler\NullHandler();
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace VendorDHL\WPDesk\Logger\WC\Exception;
class WCLoggerAlreadyCaptured extends \RuntimeException
{
}

View File

@@ -0,0 +1,132 @@
<?php
namespace VendorDHL\WPDesk\Logger\WC;
use VendorDHL\Monolog\Logger;
use VendorDHL\WPDesk\Logger\WC\Exception\WCLoggerAlreadyCaptured;
/**
* Can capture default WooCommerce logger
*
* @package WPDesk\Logger
*/
class WooCommerceCapture
{
const WOOCOMMERCE_LOGGER_FILTER = 'woocommerce_logging_class';
const WOOCOMMERCE_AFTER_IS_LOADED_ACTION = 'woocommerce_loaded';
/** @var string Minimal version of WooCommerce supported by logger capture */
const SUPPORTED_WC_VERSION = '3.5.0';
/**
* Is logger filter captured by library.
*
* @var bool
*/
private $isCaptured = \false;
/**
* Our monolog
*
* @var Logger
*/
private $monolog;
/**
* Original WC Logger
*
* @var \WC_Logger_Interface
*/
private $originalWCLogger;
/**
* WordPress hook function to return our logger
*
* @var ?callable
*/
private $captureHookFunction;
/**
* WordPress hook function to return original wc logger
*
* @var ?callable
*/
private $freeHookFunction;
public function __construct(\VendorDHL\Monolog\Logger $monolog)
{
$this->monolog = $monolog;
}
/**
* Prepares callable property captureHookFunction.
* For it to work WC have to be loaded
*/
private function prepareCaptureHookCallable()
{
$monolog = $this->monolog;
if ($this->captureHookFunction === null) {
$this->captureHookFunction = function () use($monolog) {
return new \VendorDHL\WPDesk\Logger\WC\WooCommerceMonologPlugin($monolog, $this->originalWCLogger);
};
$this->monolog->pushHandler(new \VendorDHL\WPDesk\Logger\WC\WooCommerceHandler($this->originalWCLogger));
}
}
/**
* Is this version of WooCommerce is supported by logger capture
*
* @return bool
*/
public static function isSupportedWCVersion()
{
return \class_exists(\WooCommerce::class) && \version_compare(\WooCommerce::instance()->version, self::SUPPORTED_WC_VERSION, '>=');
}
/**
* Capture WooCommerce logger and inject our decorated Logger
*/
public function captureWcLogger()
{
if (self::isSupportedWCVersion()) {
if ($this->isCaptured) {
throw new \VendorDHL\WPDesk\Logger\WC\Exception\WCLoggerAlreadyCaptured('Try to free wc logger first.');
}
if ($this->isWooCommerceLoggerAvailable()) {
$this->prepareFreeHookCallable();
$this->prepareCaptureHookCallable();
\remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
\add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
$this->isCaptured = \true;
} elseif (\function_exists('add_action')) {
\add_action(self::WOOCOMMERCE_AFTER_IS_LOADED_ACTION, [$this, 'captureWcLogger']);
} else {
$this->monolog->alert('Cannot capture WC - WordPress is not available.');
}
} else {
$this->monolog->alert('Cannot capture WC - WooCommerce version is not supported.');
}
}
/**
* Can i fetch WC Logger?
*
* @return bool
*/
private function isWooCommerceLoggerAvailable()
{
return \function_exists('wc_get_logger');
}
/**
* Prepares callable property freeHookFunction.
* For it to work WC have to be loaded
*/
private function prepareFreeHookCallable()
{
if ($this->freeHookFunction === null) {
$this->originalWCLogger = $logger = \wc_get_logger();
$this->freeHookFunction = function () use($logger) {
return $logger;
};
}
}
/**
* Remove WooCommerce logger injection
*/
public function freeWcLogger()
{
if ($this->isCaptured) {
\remove_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->captureHookFunction);
\add_filter(self::WOOCOMMERCE_LOGGER_FILTER, $this->freeHookFunction);
$this->isCaptured = \false;
}
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace VendorDHL\WPDesk\Logger\WC;
use VendorDHL\Monolog\Handler\AbstractProcessingHandler;
use VendorDHL\Monolog\Logger;
/**
* Class WooCommerceFactory
*/
class WooCommerceHandler extends \VendorDHL\Monolog\Handler\AbstractProcessingHandler
{
const DEFAULT_WC_SOURCE = 'wpdesk-logger';
/** @var \WC_Logger_Interface */
private $wc_logger;
/** @var string */
private $channel;
/**
* Writes the record down to the log of the implementing handler
*
* @param array $record
* @return void
*/
protected function write(array $record)
{
$context = \array_merge(['source' => $this->channel], $record['extra'], $record['context']);
$this->wc_logger->log($this->convertMonologLevelToWC($record['level']), $record['message'], $context);
}
/**
* @param int $level
* @return string
*/
private function convertMonologLevelToWC($level)
{
return \VendorDHL\Monolog\Logger::getLevelName($level);
}
public function __construct(\WC_Logger_Interface $originalWcLogger, string $channel = self::DEFAULT_WC_SOURCE)
{
parent::__construct();
$this->wc_logger = $originalWcLogger;
$this->channel = $channel;
}
}

View File

@@ -0,0 +1,165 @@
<?php
namespace VendorDHL\WPDesk\Logger\WC;
use VendorDHL\Monolog\Logger;
use VendorDHL\Psr\Log\LogLevel;
use WC_Log_Levels;
/**
* Can decorate monolog with WC_Logger_Interface
*
* @package WPDesk\Logger
*/
class WooCommerceMonologPlugin implements \WC_Logger_Interface
{
/** @var Logger */
private $monolog;
/** @var \WC_Logger */
private $originalWCLogger;
public function __construct(\VendorDHL\Monolog\Logger $monolog, \WC_Logger_Interface $originalLogger)
{
$this->monolog = $monolog;
$this->originalWCLogger = $originalLogger;
}
/**
* Method added for compatibility with \WC_Logger
*
* @param string $source
*/
public function clear($source = '')
{
$this->originalWCLogger->clear($source);
}
/**
* Method added for compatibility with \WC_Logger
*/
public function clear_expired_logs()
{
$this->originalWCLogger->clear_expired_logs();
}
/**
* Method for compatibility reason. Do not use.
*
* @param string $handle
* @param string $message
* @param string $level
* @return bool|void
*
* @deprecated
*/
public function add($handle, $message, $level = \WC_Log_Levels::NOTICE)
{
$this->log($message, $level);
}
/**
* System is unusable.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function emergency($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::EMERGENCY, $message, $context);
}
public function log($level, $message, $context = [])
{
$this->monolog->log($level, $message, $context);
}
/**
* Action must be taken immediately.
*
* Example: Entire website down, database unavailable, etc. This should
* trigger the SMS alerts and wake you up.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function alert($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::ALERT, $message, $context);
}
/**
* Critical conditions.
*
* Example: Application component unavailable, unexpected exception.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function critical($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::CRITICAL, $message, $context);
}
/**
* Runtime errors that do not require immediate action but should typically
* be logged and monitored.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function error($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::ERROR, $message, $context);
}
/**
* Exceptional occurrences that are not errors.
*
* Example: Use of deprecated APIs, poor use of an API, undesirable things
* that are not necessarily wrong.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function warning($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::WARNING, $message, $context);
}
/**
* Normal but significant events.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function notice($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::NOTICE, $message, $context);
}
/**
* Interesting events.
*
* Example: User logs in, SQL logs.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function info($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::INFO, $message, $context);
}
/**
* Detailed debug information.
*
* @param string $message
* @param array $context
*
* @return void
*/
public function debug($message, $context = array())
{
$this->log(\VendorDHL\Psr\Log\LogLevel::DEBUG, $message, $context);
}
}

View File

@@ -0,0 +1,127 @@
<?php
namespace VendorDHL\WPDesk\Logger\WP;
class WPCapture
{
/** @var string */
private $filename;
const LOG_DIR = 'wpdesk-logs';
public function __construct($filename)
{
$this->filename = $filename;
}
/**
* Add notice for directory.
*
* @param string $dir Directory.
*/
private function add_notice_for_dir($dir)
{
new \VendorDHL\WPDesk\Notice\Notice(\sprintf(
// Translators: directory.
\__('Can not enable WP Desk Debug log! Cannot create directory %s or this directory is not writeable!', 'woocommerce-dhl'),
$dir
), \VendorDHL\WPDesk\Notice\Notice::NOTICE_TYPE_ERROR);
}
/**
* Add notice for file.
*
* @param string $file File..
*/
private function add_notice_for_file($file)
{
new \VendorDHL\WPDesk\Notice\Notice(\sprintf(
// Translators: directory.
\__('Can not enable WP Desk Debug log! Cannot create file %s!', 'woocommerce-dhl'),
$file
), \VendorDHL\WPDesk\Notice\Notice::NOTICE_TYPE_ERROR);
}
/**
* Is debug log writable.
*
* @return bool
*/
private function is_debug_log_writable_or_show_notice()
{
$log_dir = $this->get_log_dir();
$log_file = $this->get_log_file();
$index_file = $this->get_index_file();
if (!\file_exists($log_dir)) {
if (!\mkdir($log_dir, 0777, \true)) {
$this->add_notice_for_dir($log_dir);
return \false;
}
}
if (!\file_exists($index_file)) {
$index_html = \fopen($index_file, 'w');
if (\false === $index_html) {
$this->add_notice_for_file($index_file);
return \false;
} else {
\fclose($index_html);
}
}
if (!\file_exists($log_file)) {
$log = \fopen($log_file, 'w');
if (\false === $log) {
$this->add_notice_for_file($log_file);
return \false;
} else {
\fclose($log);
}
}
if (!\is_writable($log_file)) {
$this->add_notice_for_file($log_file);
return \false;
}
return \true;
}
/**
* Init debug log file.
*/
public function init_debug_log_file()
{
if ($this->is_debug_log_writable_or_show_notice()) {
\ini_set('log_errors', 1);
\ini_set('error_log', $this->get_log_file());
}
}
/**
* Get uploads dir.
*
* @return string
*/
private function get_uploads_dir()
{
$upload_dir = \wp_upload_dir();
return \untrailingslashit($upload_dir['basedir']);
}
/**
* Get log dir.
*
* @return string
*/
private function get_log_dir()
{
return \trailingslashit($this->get_uploads_dir()) . self::LOG_DIR;
}
/**
* Get log file.
*
* @return string
*/
public function get_log_file()
{
return \trailingslashit($this->get_log_dir()) . $this->filename;
}
/**
* Get log file.
*
* @return string
*/
private function get_index_file()
{
return \trailingslashit($this->get_log_dir()) . 'index.html';
}
}

Some files were not shown because too many files have changed in this diff Show More