diff --git a/RoboFile.php b/RoboFile.php index 3cfe317e72..cdfdce3928 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -388,7 +388,7 @@ class RoboFile extends \Robo\Tasks { 'php -d memory_limit=2G '. "$dir/phpstan.phar analyse ". "--configuration $dir/tasks/phpstan/phpstan.neon ". - '--level 1 '. + '--level 2 '. "$dir/lib" ) ->dir(__DIR__ . '/tasks/phpstan') diff --git a/lib/Analytics/Reporter.php b/lib/Analytics/Reporter.php index 1b0f0fdef1..491de16c3e 100644 --- a/lib/Analytics/Reporter.php +++ b/lib/Analytics/Reporter.php @@ -34,12 +34,14 @@ class Reporter { $has_wc = $this->woocommerce_helper->isWooCommerceActive(); $wc_customers_count = 0; if ($has_wc) { - $wc_customers_count = (int)Newsletter::rawQuery( + /** @var \stdClass */ + $wc_customers = Newsletter::rawQuery( "SELECT COUNT(DISTINCT m.meta_value) as count FROM ".$wpdb->prefix."posts p ". "JOIN ".$wpdb->prefix."postmeta m ON m.post_id = p.id ". "WHERE p.post_type = 'shop_order' ". "AND m.meta_key = '_customer_user' AND m.meta_value <> 0" - )->findOne()->count; + )->findOne(); + $wc_customers_count = (int)$wc_customers->count; } return array( diff --git a/lib/Cron/Workers/SimpleWorker.php b/lib/Cron/Workers/SimpleWorker.php index 5199247a51..008b714026 100644 --- a/lib/Cron/Workers/SimpleWorker.php +++ b/lib/Cron/Workers/SimpleWorker.php @@ -116,7 +116,7 @@ abstract class SimpleWorker { $wp = new WPFunctions(); $date = Carbon::createFromTimestamp($wp->currentTime('timestamp')); // Random day of the next week - $date->setISODate($date->format('o'), $date->format('W') + 1, mt_rand(1, 7)); + $date->setISODate($date->format('o'), ((int)$date->format('W')) + 1, mt_rand(1, 7)); $date->startOfDay(); return $date; } diff --git a/lib/Cron/Workers/StatsNotifications/Worker.php b/lib/Cron/Workers/StatsNotifications/Worker.php index 2dce917e04..73d1b44f99 100644 --- a/lib/Cron/Workers/StatsNotifications/Worker.php +++ b/lib/Cron/Workers/StatsNotifications/Worker.php @@ -105,7 +105,12 @@ class Worker { ->withStatistics(); } - private function prepareContext(Newsletter $newsletter, NewsletterLink $link = null) { + /** + * @param Newsletter $newsletter + * @param \stdClass|NewsletterLink $link + * @return array + */ + private function prepareContext(Newsletter $newsletter, $link = null) { $clicked = ($newsletter->statistics['clicked'] * 100) / $newsletter->total_sent; $opened = ($newsletter->statistics['opened'] * 100) / $newsletter->total_sent; $unsubscribed = ($newsletter->statistics['unsubscribed'] * 100) / $newsletter->total_sent; diff --git a/lib/DI/ContainerFactory.php b/lib/DI/ContainerFactory.php index 0b0a1335b4..3c23c2dc73 100644 --- a/lib/DI/ContainerFactory.php +++ b/lib/DI/ContainerFactory.php @@ -2,6 +2,7 @@ namespace MailPoet\DI; +use MailPoetVendor\Symfony\Component\DependencyInjection\Container; use MailPoetVendor\Symfony\Component\DependencyInjection\ContainerBuilder; class ContainerFactory { @@ -21,6 +22,9 @@ class ContainerFactory { $this->configurator = $configurator; } + /** + * @return Container + */ function getContainer() { $dump_class = '\\'. $this->configurator->getDumpNamespace() . '\\' . $this->configurator->getDumpClassname(); if (!$this->debug && class_exists($dump_class)) { diff --git a/lib/DI/ContainerWrapper.php b/lib/DI/ContainerWrapper.php index 9b3a69fc02..39d6f73f61 100644 --- a/lib/DI/ContainerWrapper.php +++ b/lib/DI/ContainerWrapper.php @@ -4,6 +4,7 @@ namespace MailPoet\DI; use MailPoetVendor\Psr\Container\ContainerInterface; use MailPoetVendor\Psr\Container\NotFoundExceptionInterface; +use MailPoetVendor\Symfony\Component\DependencyInjection\Container; class ContainerWrapper implements ContainerInterface { @@ -60,8 +61,8 @@ class ContainerWrapper implements ContainerInterface { return self::$instance; } - private static function createPremiumContainer(ContainerInterface $free_container, $debug = false) { - $premium_container_factory = new ContainerFactory(new \MailPoet\Premium\DI\ContainerConfigurator(), $debug); + private static function createPremiumContainer(Container $free_container, $debug = false) { + $premium_container_factory = new ContainerFactory(new \MailPoet\Premium\DI\ContainerConfigurator(), $debug); $premium_container = $premium_container_factory->getContainer(); $premium_container->set(IContainerConfigurator::FREE_CONTAINER_SERVICE_SLUG, $free_container); $free_container->set(IContainerConfigurator::PREMIUM_CONTAINER_SERVICE_SLUG, $premium_container); diff --git a/lib/Models/Form.php b/lib/Models/Form.php index 0ade77700b..390f3acc46 100644 --- a/lib/Models/Form.php +++ b/lib/Models/Form.php @@ -6,6 +6,7 @@ if (!defined('ABSPATH')) exit; /** * @property string|array $settings * @property string|array $body + * @property string $name */ class Form extends Model { public static $_table = MP_FORMS_TABLE; diff --git a/lib/Models/Model.php b/lib/Models/Model.php index 0a41c84aeb..b26384f087 100644 --- a/lib/Models/Model.php +++ b/lib/Models/Model.php @@ -7,7 +7,7 @@ if (!defined('ABSPATH')) exit; /** * @method static array|string getConfig($key = null, $connection_name = self::DEFAULT_CONNECTION) * @method static null resetConfig() - * @method static \ORM forTable($table_name, $connection_name = self::DEFAULT_CONNECTION) + * @method static self forTable($table_name, $connection_name = self::DEFAULT_CONNECTION) * @method static null setDb($db, $connection_name = self::DEFAULT_CONNECTION) * @method static null resetDb() * @method static null setupLimitClauseStyle($connection_name) @@ -18,14 +18,15 @@ if (!defined('ABSPATH')) exit; * @method static array getQueryLog($connection_name = self::DEFAULT_CONNECTION) * @method array getConnectionNames() * @method $this useIdColumn($id_column) - * @method \ORM|bool findOne($id=null) - * @method static \ORM|bool findOne($id=null) + * @method $this|bool findOne($id=null) + * @method static static|bool findOne($id=null) * @method array|\IdiormResultSet findMany() * @method static array|\IdiormResultSet findMany() * @method \IdiormResultSet findResultSet() * @method array findArray() * @method static array findArray() * @method $this forceAllDirty() + * @method $this select_expr(string $expr, string $alias=null) * @method $this rawQuery($query, $parameters = array()) * @method static $this rawQuery($query, $parameters = array()) * @method $this tableAlias($alias) @@ -35,11 +36,12 @@ if (!defined('ABSPATH')) exit; * @method static $this select($column, $alias=null) * @method $this selectExpr($expr, $alias=null) * @method static $this selectExpr($expr, $alias=null) - * @method \ORM selectMany(...$values) - * @method static \ORM selectMany(...$values) - * @method \ORM selectManyExpr($values) + * @method $this selectMany(...$values) + * @method static static selectMany(...$values) + * @method static selectManyExpr($values) * @method $this rawJoin($table, $constraint, $table_alias, $parameters = array()) * @method $this innerJoin($table, $constraint, $table_alias=null) + * @method $this join(string $table, string $constraint, $table_alias=null) * @method $this leftOuterJoin($table, $constraint, $table_alias=null) * @method $this rightOuterJoin($table, $constraint, $table_alias=null) * @method $this fullOuterJoin($table, $constraint, $table_alias=null) @@ -51,8 +53,8 @@ if (!defined('ABSPATH')) exit; * @method static $this whereNotEqual($column_name, $value=null) * @method $this whereIdIs($id) * @method $this whereAnyIs($values, $operator='=') - * @method array|string whereIdIn($ids) - * @method static array|string whereIdIn($ids) + * @method $this whereIdIn($ids) + * @method static static whereIdIn($ids) * @method $this whereLike($column_name, $value=null) * @method $this whereNotLike($column_name, $value=null) * @method $this whereGt($column_name, $value=null) @@ -94,16 +96,21 @@ if (!defined('ABSPATH')) exit; * @method static $this clearCache($table_name = null, $connection_name = self::DEFAULT_CONNECTION) * @method bool setExpr($key, $value = null) * @method bool isDirty($key) - * @method static ORMWrapper filter(...$args) - * @method \ORMWrapper hasMany($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) - * @method \ORMWrapper hasManyThrough($associated_class_name, $join_class_name=null, $key_to_base_table=null, $key_to_associated_table=null, $key_in_base_table=null, $key_in_associated_table=null, $connection_name=null) - * @method \ORMWrapper hasOne($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) - * @method \ORMWrapper|bool create($data=null) - * @method static \ORMWrapper|bool create($data=null) + * @method static static filter(...$args) + * @method $this hasMany($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) + * @method $this hasManyThrough($associated_class_name, $join_class_name=null, $key_to_base_table=null, $key_to_associated_table=null, $key_in_base_table=null, $key_in_associated_table=null, $connection_name=null) + * @method $this hasOne($associated_class_name, $foreign_key_name=null, $foreign_key_name_in_current_models_table=null, $connection_name=null) + * @method $this|bool create($data=null) + * @method static $this|bool create($data=null) * @method int count() * @method static int count() + * @method static static limit(int $limit) + * @method static static distinct() + * @method $this set(string|array $key, string|null $value = null) * * @property string|null $created_at + * @property string|null $updated_at + * @property string|null $id */ class Model extends \Sudzy\ValidModel { const DUPLICATE_RECORD = 23000; @@ -129,7 +136,7 @@ class Model extends \Sudzy\ValidModel { * * @param array $data * @param boolean $keys - * @param callable $onCreate + * @param callable|bool $onCreate * @return self */ static protected function _createOrUpdate($data = array(), $keys = false, $onCreate = false) { diff --git a/lib/Models/Newsletter.php b/lib/Models/Newsletter.php index 1ca0c31a1d..034c759bb0 100644 --- a/lib/Models/Newsletter.php +++ b/lib/Models/Newsletter.php @@ -22,10 +22,12 @@ if (!defined('ABSPATH')) exit; * @property int $children_count * @property bool|array $statistics * @property string $deleted_at - * @property int $children_count * @property int $total_sent * @property int $total_scheduled * @property array $segments + * @property string $subject + * @property string $body + * @property string|null $schedule */ class Newsletter extends Model { public static $_table = MP_NEWSLETTERS_TABLE; @@ -585,16 +587,17 @@ class Newsletter extends Model { } function wasScheduledForSubscriber($subscriber_id) { - $count = (int)SendingQueue::rawQuery( + /** @var \stdClass */ + $queue = SendingQueue::rawQuery( "SELECT COUNT(*) as count FROM `" . SendingQueue::$_table . "` JOIN `" . ScheduledTask::$_table . "` ON " . SendingQueue::$_table . ".task_id = " . ScheduledTask::$_table . ".id JOIN `" . ScheduledTaskSubscriber::$_table . "` ON " . ScheduledTask::$_table . ".id = " . ScheduledTaskSubscriber::$_table . ".task_id WHERE " . ScheduledTaskSubscriber::$_table . ".subscriber_id = " . $subscriber_id . " AND " . SendingQueue::$_table . ".newsletter_id = " . $this->id - )->findOne()->count; + )->findOne(); - return $count > 0; + return ((int)$queue->count) > 0; } diff --git a/lib/Models/NewsletterLink.php b/lib/Models/NewsletterLink.php index 867ae74557..739ad73e7e 100644 --- a/lib/Models/NewsletterLink.php +++ b/lib/Models/NewsletterLink.php @@ -3,9 +3,19 @@ namespace MailPoet\Models; if (!defined('ABSPATH')) exit; +/** + * @property int $newsletter_id + * @property int $queue_id + * @property string $url + * @property string $hash + */ class NewsletterLink extends Model { public static $_table = MP_NEWSLETTER_LINKS_TABLE; + /** + * @param Newsletter $newsletter + * @return \stdClass|null + */ static function findTopLinkForNewsletter(Newsletter $newsletter) { $link = self::selectExpr('links.*') ->selectExpr('count(*)', 'clicksCount') diff --git a/lib/Models/NewsletterTemplate.php b/lib/Models/NewsletterTemplate.php index 25b9ad488a..834050a487 100644 --- a/lib/Models/NewsletterTemplate.php +++ b/lib/Models/NewsletterTemplate.php @@ -3,6 +3,15 @@ namespace MailPoet\Models; if (!defined('ABSPATH')) exit; +/** + * @property string $name + * @property int|null $newsletter_id + * @property string $categories + * @property string $description + * @property string|null $body + * @property string|null $thumbnail + * @property int|null $readonly + */ class NewsletterTemplate extends Model { public static $_table = MP_NEWSLETTER_TEMPLATES_TABLE; diff --git a/lib/Models/ScheduledTask.php b/lib/Models/ScheduledTask.php index 38324bf467..71a18da6f6 100644 --- a/lib/Models/ScheduledTask.php +++ b/lib/Models/ScheduledTask.php @@ -9,7 +9,10 @@ if (!defined('ABSPATH')) exit; /** * @property int $id * @property string $processed_at + * @property string|null $status + * @property string|null $type * @property int $priority + * @property string $scheduled_at */ class ScheduledTask extends Model { public static $_table = MP_SCHEDULED_TASKS_TABLE; diff --git a/lib/Models/Segment.php b/lib/Models/Segment.php index 2c3ef33b82..d9f15e8c77 100644 --- a/lib/Models/Segment.php +++ b/lib/Models/Segment.php @@ -4,8 +4,10 @@ namespace MailPoet\Models; if (!defined('ABSPATH')) exit; /** - * @property int $id * @property array $subscribers_count + * @property string $name + * @property string $type + * @property string $description */ class Segment extends Model { static $_table = MP_SEGMENTS_TABLE; diff --git a/lib/Models/SendingQueue.php b/lib/Models/SendingQueue.php index 05aa5d3cec..8073b31469 100644 --- a/lib/Models/SendingQueue.php +++ b/lib/Models/SendingQueue.php @@ -9,11 +9,15 @@ if (!defined('ABSPATH')) exit; /** * @property int $count_processed + * @property int $count_to_process * @property int $count_total * @property string $newsletter_rendered_body + * @property string $newsletter_rendered_subject * @property int $task_id + * @property int $newsletter_id * @property string|object $meta * @property string|array $subscribers + * @property string|null $deleted_at */ class SendingQueue extends Model { public static $_table = MP_SENDING_QUEUES_TABLE; diff --git a/lib/Models/Setting.php b/lib/Models/Setting.php index 822796f772..521ef3b4e2 100644 --- a/lib/Models/Setting.php +++ b/lib/Models/Setting.php @@ -5,6 +5,10 @@ use MailPoet\Settings\SettingsController; if (!defined('ABSPATH')) exit; +/** + * @property string $name + * @property string|null $value + */ class Setting extends Model { public static $_table = MP_SETTINGS_TABLE; diff --git a/lib/Models/StatisticsClicks.php b/lib/Models/StatisticsClicks.php index 389b2d3013..7b3c87016e 100644 --- a/lib/Models/StatisticsClicks.php +++ b/lib/Models/StatisticsClicks.php @@ -3,6 +3,13 @@ namespace MailPoet\Models; if (!defined('ABSPATH')) exit; +/** + * @property int $newsletter_id + * @property int $subscriber_id + * @property int $queue_id + * @property int $link_id + * @property int $count + */ class StatisticsClicks extends Model { public static $_table = MP_STATISTICS_CLICKS_TABLE; diff --git a/lib/Models/Subscriber.php b/lib/Models/Subscriber.php index c8dae6912a..f38a2053e2 100644 --- a/lib/Models/Subscriber.php +++ b/lib/Models/Subscriber.php @@ -11,6 +11,15 @@ if (!defined('ABSPATH')) exit; /** * @property int $id * @property string $email + * @property string $first_name + * @property string $last_name + * @property string $status + * @property string|null $subscribed_ip + * @property string|null $confirmed_ip + * @property string|null $confirmed_at + * @property string|null $deleted_at + * @property string|null $source + * @property int $count_confirmations * @property int $wp_user_id * @property array $segments * @property array $subscriptions @@ -26,6 +35,9 @@ class Subscriber extends Model { const STATUS_BOUNCED = 'bounced'; const SUBSCRIBER_TOKEN_LENGTH = 6; + /** @var string|bool */ + public $token; + function __construct() { parent::__construct(); diff --git a/lib/Models/SubscriberCustomField.php b/lib/Models/SubscriberCustomField.php index 9cf260181a..25cd5dfb00 100644 --- a/lib/Models/SubscriberCustomField.php +++ b/lib/Models/SubscriberCustomField.php @@ -5,6 +5,11 @@ use MailPoet\Util\Helpers; if (!defined('ABSPATH')) exit; +/** + * @property int $subscriber_id + * @property int $custom_field_id + * @property string $value + */ class SubscriberCustomField extends Model { public static $_table = MP_SUBSCRIBER_CUSTOM_FIELD_TABLE; diff --git a/lib/Router/Endpoints/ViewInBrowser.php b/lib/Router/Endpoints/ViewInBrowser.php index 387b8e459b..7f386e72cd 100644 --- a/lib/Router/Endpoints/ViewInBrowser.php +++ b/lib/Router/Endpoints/ViewInBrowser.php @@ -43,6 +43,10 @@ class ViewInBrowser { $this->_abort(); } + /** + * @param \stdClass $data + * @return bool|\stdClass + */ function _validateBrowserPreviewData($data) { // either newsletter ID or hash must be defined, and newsletter must exist if (empty($data->newsletter_id) && empty($data->newsletter_hash)) return false; diff --git a/lib/Statistics/Track/Clicks.php b/lib/Statistics/Track/Clicks.php index eac7d33a34..5388893d68 100644 --- a/lib/Statistics/Track/Clicks.php +++ b/lib/Statistics/Track/Clicks.php @@ -8,6 +8,9 @@ use MailPoet\Newsletter\Shortcodes\Shortcodes; if (!defined('ABSPATH')) exit; class Clicks { + /** + * @param \stdClass $data + */ function track($data) { if (!$data || empty($data->link)) { return $this->abort(); diff --git a/lib/Tasks/Sending.php b/lib/Tasks/Sending.php index 38b653ce12..4ca50d2802 100644 --- a/lib/Tasks/Sending.php +++ b/lib/Tasks/Sending.php @@ -13,6 +13,9 @@ if (!defined('ABSPATH')) exit; /** * A facade class containing all necessary models to work with a sending queue + * @property string $status + * @property int $task_id + * @property int $id */ class Sending { const TASK_TYPE = 'sending'; diff --git a/lib/Util/ConflictResolver.php b/lib/Util/ConflictResolver.php index 37b91c139d..30d3be856a 100644 --- a/lib/Util/ConflictResolver.php +++ b/lib/Util/ConflictResolver.php @@ -62,6 +62,7 @@ class ConflictResolver { // unload all styles except from the list of allowed $dequeue_styles = function() use($_this) { global $wp_styles; + if (!isset($wp_styles->registered)) return; if (empty($wp_styles->queue)) return; foreach ($wp_styles->queue as $wp_style) { if (empty($wp_styles->registered[$wp_style])) continue; diff --git a/lib/Util/Polyfills.php b/lib/Util/Polyfills.php index 7ab60a8d7e..f5a045a611 100644 --- a/lib/Util/Polyfills.php +++ b/lib/Util/Polyfills.php @@ -17,7 +17,7 @@ if (!function_exists('mb_convert_encoding')) { } if (!function_exists('mb_strtoupper')) { - function mb_strtoupper($s, $encoding = null) { + function mb_strtoupper($s, $encoding = 'UTF-8') { return MbstringPolyfill::mb_strtoupper($s, $encoding); } } diff --git a/lib/Util/Sudzy/Engine.php b/lib/Util/Sudzy/Engine.php index 20a8084b62..20f1f09045 100644 --- a/lib/Util/Sudzy/Engine.php +++ b/lib/Util/Sudzy/Engine.php @@ -41,9 +41,10 @@ class Engine } /** - * @param string label used to call function - * @param Callable function with params (value, additional params as array) - */ + * @param string $label label used to call function + * @param Callable $function function with params (value, additional params as array) + * @throws \Exception + */ public function addValidator($label, $function) { if (isset($this->_checks[$label])) throw new \Exception(); diff --git a/tasks/phpstan/phpstan.neon b/tasks/phpstan/phpstan.neon index 4369066f6b..3c96f35eef 100644 --- a/tasks/phpstan/phpstan.neon +++ b/tasks/phpstan/phpstan.neon @@ -4,4 +4,5 @@ parameters: ignoreErrors: - '#Function members_register_.+ not found#' - '#MailPoet\\Premium\\DI\\ContainerConfigurator not found#' # this class is not available when premium is not active + - '#Call to an undefined method IdiormResultSet::set()#' reportUnmatchedIgnoredErrors: false