Szybkie posty

Jeżeli coś jest wartego uwagi a nie jest to materiał na pełnoprawnwgo posta na blogu to będę starać się to umieszczać w tym miejscu.

#ajax #apache #behat #bitbacket #bootstrap #composer #cookies #cqrs #css #css flex #ct8 #curl #docker #doctrine #edukacja #enet #enp sla #filmy #firma #funkcje php #git #google #htaccess #html #inne #javascript #jedzenie #jquery #js/jquery #kawały #krypto #laravel #linux #oop #pdo #php #php wzorce narzędzia #phpmyadmin #phpspec #phpstan #phpstorm #phpunit #podcast #rabbit #redis #seo #soap #sql #symfony #szukanie po stringach w php #twig #virtual host #visual studio code #vue #wamp #windows #wino-nalewki #wyrazenia regularne #wzorce projektowe #xml #xxx #zdjecia #złote myśli
  • Szukasz po tagu: php
  • Ilość rekordów w bazie: 109

statyczny cache vs zwykły w php

<?php

class test {
	private static $cache = null;
	
	public function getData() {
		if(null == self::$cache) {
			self::$cache = $this->getFromDb();
		}
		
		return self::$cache;
	}
	
	public function getFromDb() {
		echo 'pobieranie danych'."\n";
		return 1234;
	}
}


class test2 {
	private  $cache = null;
	
	public function setCache(){
		self::$cache = 123;
	}
	
	public function getData() {
		if(null == $this->cache) {
			$this->cache = $this->getFromDb();
		}
		
		return $this->cache;
	}
	
	public function getFromDb() {
		echo 'pobieranie danych2222'."\n";
		return 12345678;
	}
}

$test = new test();
echo $test->getData();
$test2 = new test();
echo $test2->getData();
echo "\n\n\n";
//==============
$test3 = new test2();
echo $test3->getData() ."\n";
$test3 = new test2();
echo $test3->getData();

serializacja dostepne parametry

    /**
     * @Assert\GreaterThan(0)
     * @SerializedName("productId")
     * @OA\Property(property="productId")
     */
    public readonly ?int $productId;

zaokrąglenie przy wyliczaniu ceny netto

<?php

declare(strict_types=1);

namespace Module\Service\Domain\WriteModel\Service\Calculator;

use Module\Service\Domain\WriteModel\Model\Price;

final class TaxCalculator
{
    public static function calculateNetPrice(int $grossPrice, int $tax): int
    {
        if ($tax <= 0 || $grossPrice <= 0) {
            return $grossPrice;
        }

        $taxPercent = $tax / Price::ONE_HUNDRED_PERCENT;
        $netPrice = ($grossPrice / ($taxPercent + 1));

        return (int) round($netPrice);
    }
}
Price::ONE_HUNDRED_PERCENT = 10000

 


warunkowa wymagalność

    public function onSubmit(FormEvent $event): void
    {
        /** @var ENP0026MeBox $meBox */
        $meBox = $event->getData();
        $form = $event->getForm();
        if (!$meBox->isActive()) {
            return;
        }

        $requiredFormData[] = $form['code'];
        $requiredFormData[] = $form['address']['street'];
        $requiredFormData[] = $form['address']['houseNumber'];
        $requiredFormData[] = $form['address']['lat'];
        $requiredFormData[] = $form['address']['lng'];

        foreach ($requiredFormData as $single) {
            if (empty($single->getData())) {
                $single->addError(
                    new FormError($this->translator->trans('pos.me_box_required_field', [], 'EnpPOSBundle'))
                );
            }
        }
    }

mikr optymalizacje w php

link


bugtrace ścieżka wywołań do pliku

$backTrace = debug_backtrace();
$files = array_column($backTrace, 'file');
$lines = array_column($backTrace, 'line');
$backtraceToLogs = array_combine($files, $lines);

array column zamiast pętli

<?php
// Array representing a possible record set returned from a database
$records = array(
    array(
        'id' => 2135,
        'first_name' => 'John',
        'last_name' => 'Doe',
    ),
    array(
        'id' => 3245,
        'first_name' => 'Sally',
        'last_name' => 'Smith',
    ),
    array(
        'id' => 5342,
        'first_name' => 'Jane',
        'last_name' => 'Jones',
    ),
    array(
        'id' => 5623,
        'first_name' => 'Peter',
        'last_name' => 'Doe',
    )
);
 
$first_names = array_column($records, 'first_name', 'id');
print_r($first_names);
       
//=================

foreach ($result as $status) {
    $statuses[$status['id']] = sprintf('%s [%s]', $status['name'], $status['id']);
}

return $statuses;
        
return array_column($result, 'name', 'id');

callback w commandzie

inal class UpdateUnpaidOrdersMessage implements CommandMessageInterface
{
    private int $fetchInterval;
    private int $websiteId;
    private int $limit;
    private ArrayCollection $responseMessages;
    private $onProcessOrder;

    public function __construct(
        int $fetchInterval,
        int $websiteId,
        int $limit,
        $onProcessOrder = null
    ) {
        $this->fetchInterval = $fetchInterval;
        $this->websiteId = $websiteId;
        $this->limit = $limit;
        $this->onProcessOrder = $onProcessOrder;
        $this->responseMessages = new ArrayCollection();
    }
}
        $message = new UpdateUnpaidOrdersMessageV2(
            $fetchInterval,
            $websiteId,
            $limit,
            function (array $ceneoOrder) use ($output, &$index) {
                $timestamp = (int) str_replace(['/Date(', ')'], ['', ''], $ceneoOrder['CreatedDate']);
                $createdDate = new DateTime();
                $createdDate->setTimestamp((int) ($timestamp / 1000));

                $output->writeln("Index: {$index}");
                $output->writeln("Id: {$ceneoOrder['Id']}");
                $output->writeln("ShopOrderId: {$ceneoOrder['ShopOrderId']}");
                $output->writeln("DisplayedOrderId: {$ceneoOrder['DisplayedOrderId']}");
                $output->writeln("OrderStateId: {$ceneoOrder['OrderStateId']}");
                $output->writeln("PaymentMethodId: {$ceneoOrder['PaymentMethodId']}");
                $output->writeln("PaymentTypeId: {$ceneoOrder['PaymentTypeId']}");
                $output->writeln("OrderValue: {$ceneoOrder['OrderValue']}");
                $output->writeln("CreatedDate: {$ceneoOrder['CreatedDate']} - {$createdDate->format('Y-m-d H:i:s')}");
                $output->writeln('------------------------------');
                $index++;
            }
        );
    private function onProcessOrder(UpdateUnpaidOrdersMessage $message, array $ceneoOrder): void
    {
        $onProcessOrder = $message->onProcessOrder();
        if (!is_callable($onProcessOrder)) {
            return;
        }

        $onProcessOrder($ceneoOrder);
    }

 


tylko dwie cyfry po kropce przecinku

<?php
$test = sprintf('%.2f',100/30);
var_dump($test);

//"3.33"

idk z kolekcji doctrine

$ordersIds = $orders->map(fn($order) => $order->getId())->getValues();

inty po przecinku trim i explode

<?php
$s = "1,2,3, 58, 2 ";
$arrayMapped = array_map(fn($item) => (int) trim($item), explode(',', $s));
var_dump($arrayMapped);

wynik po właściwości obiektu

<?php

Class Car {
	private $id;
	
	public function __construct($id){
		$this->id = $id;
	}
	
	public function getId(){
		return $this->id;
	}
}

$cars = [ new Car(3), new Car(4)];


$res = array_combine(
	array_map(function ($o) { 
		return $o->getId(); 
	}, $cars), $cars
);

//
array(2) {
  [3]=>
  object(Car)#1 (1) {
    ["id":"Car":private]=>
    int(3)
  }
  [4]=>
  object(Car)#2 (1) {
    ["id":"Car":private]=>
    int(4)
  }
}

read model doctrine symfony

class StatusFinder extends FinderAbstract
{
    public function getTableName(): string
    {
        return 'payment_mokka_status';
    }

    public function getAlias(): string
    {
        return 'pmos';
    }

    /**
     * @param string $orderNumber
     *
     * @return StatusReadModel[]
     */
    public function getStatusCollection(string $orderNumber): array
    {
        return array_map(
            static fn($order) => StatusReadModel::create($order),
            $this->getQueryBuilder()
                ->andWhere(sprintf('%s.order_number = :order_id', $this->getAlias()))
                ->setParameter('order_id', $orderNumber, PDO::PARAM_STR)
                ->execute()
                ->fetchAll()
        );
    }

    public function getLatestStatus(string $orderNumber): ?StatusReadModel
    {
        $qb = $this->getQueryBuilder()
            ->andWhere(sprintf('%s.order_number = :order_id', $this->getAlias()))
            ->orderBy(sprintf('%s.id', $this->getAlias()), 'desc')
            ->setMaxResults(1)
            ->setParameter('order_id', $orderNumber, PDO::PARAM_STR)
            ->execute();
        $data = $qb->fetch();

        if ($data) {
            return StatusReadModel::create($data);
        }

        return null;
    }
}
class StatusReadModel
{
    private int $id;

    private string $orderNumber;

    private array $response;

    private DateTimeInterface $createdAt;

    private function __construct(int $id, string $orderNumber, array $response, DateTimeInterface $createdAt)
    {
        $this->id = $id;
        $this->orderNumber = $orderNumber;
        $this->response = $response;
        $this->createdAt = $createdAt;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getOrderNumber(): string
    {
        return $this->orderNumber;
    }

    public function getResponse(): array
    {
        return $this->response;
    }

    public function getCreatedAt(): DateTimeInterface
    {
        return $this->createdAt;
    }

    public static function create(array $data): self
    {
        return new self(
            (int)($data['id'] ?? 0),
            $data['order_number'],
            json_decode($data['response'], true),
            new DateTime($data['created_at'])
        );
    }

    public function getOrderData(): array
    {
        return $this->response[ApiParameterEnum::CURRENT_ORDER] ?? [];
    }

    public function getOrderStatus(): ?string
    {
        return $this->response[ApiParameterEnum::CURRENT_ORDER][ApiParameterEnum::STATUS] ?? null;
    }

    public function paymentHasBeenApproved(): bool
    {
        return ($this->getOrderData()[ApiParameterEnum::DECISION] ?? null) === PaymentDecisionEnum::APPROVED
            && !empty($this->getPaymentId());
    }

    public function getPaymentId(): ?string
    {
        return $this->getOrderData()[ApiParameterEnum::PAYMENT_ID] ?? null;
    }
}

jit ustawienia

opcache.jit = 1205 - all code is JIT compiled
opcache.jit = 1235 - only selected code portions (based on their relative use) are passed to the JIT compilation
opcache.jit = 1255 - application code is tracked for compilation by JIT and selected parts of the code are transferred to the compiler
No. Value Description
1. disable JIT is completely disabled and cannot be enabled at run time.
2. off JIT is disabled but can be enabled at run time.
3. on or tracing Enables the JIT in tracing mode. This is the same as CRTO = 1254.
4. function Enables the JIT in function mode. This is the same as CRTO = 1205.
5. 4-digit integer (CRTO) Each digit is used to define:
1. CPU-specific optimization flags (C)
2. Register allocation (R)
3. Trigger (T)
4. Optimization level (O)

 


fitrowanie kluczy z dodawaniem prefixu

$data = [
    ['test' => 'xxxx'],
    ['test' => 'aaaa'],
    ['test' => 'z2Gtui345mxQp'],
    ['test222' => 'z2Gtui345mxQp']
];
$key = 'test';
$groupedData = array_map(fn ($item) => sprintf('API_%s', ($item[$key] ?? '')), $data);
var_dump($groupedData);
$groupedData2 = array_map(function ($item) use ($key) {
    return sprintf('API_%s', $item[$key] ?? '');
}, $data);
var_dump($groupedData2);
array(4) {
  [0]=>
  string(8) "API_xxxx"
  [1]=>
  string(8) "API_aaaa"
  [2]=>
  string(17) "API_z2Gtui345mxQp"
  [3]=>
  string(4) "API_"
}

redirect post do przetestowania

/**
  * Redirect with POST data.
  *
  * @param string $url URL.
  * @param array $post_data POST data. Example: ['foo' => 'var', 'id' => 123]
  * @param array $headers Optional. Extra headers to send.
  */
public function redirect_post($url, array $data, array $headers = null) {
  $params = [
    'http' => [
      'method' => 'POST',
      'content' => http_build_query($data)
    ]
  ];

  if (!is_null($headers)) {
    $params['http']['header'] = '';
    foreach ($headers as $k => $v) {
      $params['http']['header'] .= "$k: $v\n";
    }
  }

  $ctx = stream_context_create($params);
  $fp = @fopen($url, 'rb', false, $ctx);

  if ($fp) {
    echo @stream_get_contents($fp);
    die();
  } else {
    // Error
    throw new Exception("Error loading '$url', $php_errormsg");
  }
}

komentarze zapis parametrów z kluczami typy

    /**
     * @param ArrayCollection<WarrantyStructureDTO> $structures
     */
    /**
     * @param int $websiteId
     *
     * @return array<int, DeliveryTimeDTO>
     */
    public function get(int $websiteId): array
**
 * @param Foo[] $listOfLists
 */
public function test(array $listOfLists) {}
/**
* @return TransportGroupDTO[]|null
*/
public function getTransportGroups(): ?array
 /**
     * @param int[] $ids
     *
     * @return array<int, OrderItem>
     */
    public function getItemByIdsGroupedByIds(array $ids): array
    /**
     * @param int[] $ids
     *
     * @return OrderItem[]
     */
    public function getItemByIds(array $ids): array
    /**
     * @param ArrayCollection<array{elements: CustomerOrderListDTO[], total_count: int}> $customerOrderList
     * @param Collection<OrderInterface> $orderCollection
     */
    public function decorate(ArrayCollection $customerOrderList, Collection $orderCollection): void
/**
 * @method CartPromotion|false first()
 * @method CartPromotion[] toArray()
 * @extends ArrayCollection<int, CartPromotion>
 */
final class CartPromotionBag extends ArrayCollection
{
}
    /**
     * @return array<array<AdditionalInterface>>
     */
    public function getAllAdditionalsCollecttion(): array
    {
        return $this->toArray();
    }

zmienna odrazu w ifie

 if (($realizePos = $cart->getRealizePos()) instanceof PosInterface) {

decorator magiczne wolacnzie metody

final class ProtectiveFoilOfferCollectionCacheLoaderDecorator implements ProtectiveFoilOfferCollectionLoaderInterface
{
    private CacheProviderInterface $cacheProvider;

    private ProtectiveFoilOfferCollectionLoaderInterface $protectiveFoilOfferCollectionLoader;

    public function __construct(
        ProtectiveFoilOfferCollectionLoaderInterface $protectiveFoilOfferCollectionLoader,
        CacheProviderInterface $cacheProvider
    ) {
        $this->protectiveFoilOfferCollectionLoader = $protectiveFoilOfferCollectionLoader;
        $this->cacheProvider = $cacheProvider;
    }

    public function loadByFoilIndexesAndWebsite(
        array $foilIndexes,
        int $websiteId
    ): ProtectiveFoilOfferDTOCollection {
        return $this->cacheProvider->load(
            sprintf('protecitve_foil_offer_collection_and_website_%s_%d', implode('_', $foilIndexes), $websiteId),
            CacheLifetime::THREE_MINUTES,
            function () use ($foilIndexes, $websiteId): ProtectiveFoilOfferDTOCollection {
                return $this->protectiveFoilOfferCollectionLoader->loadByFoilIndexesAndWebsite(
                    $foilIndexes,
                    $websiteId
                );
            }
        );
    }


    public function __call(string $name, array $arguments)
    {
        return call_user_func_array([$this->protectiveFoilOfferCollectionLoader, $name], $arguments);
    }
}

sortowanie tablicy obiektów drugą tablicą

$posP600Stock = [];//tablica obiektów w której każyd posiada metodę getWarehouseId
$warehouseIdsPriorities = [34,33,12,6];//priorytety sortowania !!! pamietaj o array flip !!! 

usort(
    $posP600Stock,
    function ($d1, $d2) use ($warehouseIdsPriorities) {
       return $warehouseIdsPriorities[$d1->getWarehouseId()] >= $warehouseIdsPriorities[$d2->getWarehouseId()] ? 1 : -1;
//lub return $warehouseIdsPriorities[$d1->getWarehouseId()] <=> $warehouseIdsPriorities[$d2->getWarehouseId()] ;
    }
);

//wynik pososrtowany po wartościach z drugiej tablicy
<?php
$data = [
  ['mag' => 3, 'value' => 22],  
  ['mag' => 3, 'value' => 33],  
  ['mag' => 5, 'value' => 44],  
  ['mag' => 9, 'value' => 4444],  
  ['mag' => 3, 'value' => 55],  
  ['mag' => 4, 'value' => 554343],  
  ['mag' => 9, 'value' => 234324],  
];

$sort = [9,3,4,5];

$orderIdKeys  = array_flip($sort);

usort($data, function ($u1, $u2)  use ($orderIdKeys) {
   return $orderIdKeys[$u1['mag']] >= $orderIdKeys[$u2['mag']] ?  1 : -1;
   //lub  $orderIdKeys[$u1['mag']] <=> $orderIdKeys[$u2['mag']];
});


var_dump($data);

repozytoria

https://github.com/hgraca/explicit-architecture-php/tree/master/src

sortowanie z zachowaniem kluczy

$servicesIds = [];

foreach ($conflictedData as $key => $singleGroup) {
   uasort($singleGroup, fn($a, $b) => $a->getCreatedAt() > $b->getCreatedAt());
   unset($conflictedData[$key][array_key_first($singleGroup)]);
   $servicesIds[] = array_keys($conflictedData[$key]);
}

return array_merge(...$servicesIds);

merge poza pętlą

    public function xxx(OrderInterface $order, ?string $postCodeToCheck): void
    {
        $returnOfDamagedEquipmentServicesToRemoveLocal = [];

        foreach ($this->guardsCollection as $singleGuard) {
                $returnOfDamagedEquipmentServicesToRemoveLocal[] = $singleGuard->getReturnOfDamagedEquipmentServicesToRemove();
            }
        }

        if (empty($returnOfDamagedEquipmentServicesToRemoveLocal)) {
            return;
        }

        $this->returnOfDamagedEquipmentServicesToRemove = array_merge(
            ...$returnOfDamagedEquipmentServicesToRemoveLocal
        );
    }

ustawienie wersji phpna linuxie

sudo update-alternatives --config php

update-alternatives --set php /usr/bin/php7.4

 

//aktywacja wersji
sudo a2enmod php8.0

dezaktywacja
//sudo a2dismod php8.0

Php ciekawostki

https://stackoverflow.com/questions/3819398/php-exec-command-or-similar-to-not-wait-for-resulthttps://stackoverflow.com/questions/3819398/php-exec-command-or-similar-to-not-wait-for-result


pierwszy klucz z tablicy w php

<?php
$transport = ['123' => 123333, 1236 => 'asdad'];
$mode = current($transport);

var_dump($mode);//123333

tablica na obiekt w php

<?php
class ArrayToObject
{
    public static function convertToObject(array $array): stdClass
    {
        $object = new stdClass();

        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $value = static::convertToObject($value);
            }

            $object->$key = $value;
        }

        return $object;
    }
}

$array = [
    'e1' => ['nume' => 'Nitu', 'prenume' => 'Andrei', 'sex' => 'm', 'varsta' => 23, 'data' => [
        'page' => 1,
        'ajax' => true,
        'title' => 'test 123'
    ]],
    'e2' => ['nume' => 'Nae', 'prenume' => 'Ionel', 'sex' => 'm', 'varsta' => 27],
    'e3' => ['nume' => 'Noman', 'prenume' => 'Alice', 'sex' => 'f', 'varsta' => 22],
    'e4' => ['nume' => 'Geangos', 'prenume' => 'Bogdan', 'sex' => 'm', 'varsta' => 23],
    'e5' => ['nume' => 'Vasile', 'prenume' => 'Mihai', 'sex' => 'm', 'varsta' => 25]
];


$obj = ArrayToObject::convertToObject($array);

echo '<pre>';
var_dump($obj->e1->data->title);
echo '</pre>';
?>

kalkulator kilometrów na podstawie długości i szerokosci geograficznej

class DistanceCalculator
{
    private const EARTH_RADIUS = 6371.009;

    public function calculate(CoordinableInterface $from, CoordinableInterface $to): float
    {
        return $this->calculateBetweenPoints((float)$from->getLat(), (float)$from->getLng(), (float)$to->getLat(), (float)$to->getLng());
    }

    public function calculateBetweenPoints(
        float $latitudeFrom,
        float $longitudeFrom,
        float $latitudeTo,
        float $longitudeTo
    ): float {
        $latFrom = deg2rad($latitudeFrom);
        $lonFrom = deg2rad($longitudeFrom);
        $latTo = deg2rad($latitudeTo);
        $lonTo = deg2rad($longitudeTo);

        $latDelta = $latTo - $latFrom;
        $lonDelta = $lonTo - $lonFrom;

        $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));

        return $angle * static::EARTH_RADIUS;
    }
}

paginator tablicy

class ArrayPaginator
{
    public function getPaginatedList(array $data, int $page, int $limit): array
    {
        if (false === $this->isValidPaginationInput($page, $limit)) {
            return [];
        }

        $offset = ($page - 1) * $limit;

        return array_slice($data, $offset, $limit);
    }

    private function isValidPaginationInput(int $page, int $limit): bool
    {
        return $page > 0 && $limit > 0;
    }
}

wzorowe repo

https://gitlab.enp.me/mshp/adafir/-/merge_requests/73672

https://gitlab.enp.me/mshp/adafir/-/merge_requests/73141

https://gitlab.enp.me/mshp/adafir/-/merge_requests/73886

https://gitlab.enp.me/mshp/adafir/-/merge_requests/73904

https://gitlab.enp.me/mshp/adafir/-/merge_requests/74201


rabbit przykład

//composer.json

{
    "require": {
        "php-amqplib/php-amqplib": "^2.11"
    }
}

//publisher.php

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

require_once(__DIR__ . '/vendor/autoload.php');

define("RABBITMQ_HOST", "localhost");
define("RABBITMQ_PORT", 5672);
define("RABBITMQ_USERNAME", "guest");
define("RABBITMQ_PASSWORD", "guest");
define("RABBITMQ_QUEUE_NAME", "task_queue");

$connection = new \PhpAmqpLib\Connection\AMQPStreamConnection(
    RABBITMQ_HOST,
    RABBITMQ_PORT,
    RABBITMQ_USERNAME,
    RABBITMQ_PASSWORD
);

$channel = $connection->channel();

# Create the queue if it does not already exist.
$channel->queue_declare(
    $queue = RABBITMQ_QUEUE_NAME,
    $passive = false,
    $durable = true,
    $exclusive = false,
    $auto_delete = false,
    $nowait = false,
    $arguments = null,
    $ticket = null
);

$jobId = 0;

while (true) {
    $jobArray = [
        'id' => $jobId++,
        'task' => 'sleep',
        'sleep_period' => rand(0, 3)
    ];

    $msg = new \PhpAmqpLib\Message\AMQPMessage(
        json_encode($jobArray, JSON_UNESCAPED_SLASHES),
        ['delivery_mode' => 2] # Non-persistent (1) or persistent (2).
    );

    $channel->basic_publish($msg, '', RABBITMQ_QUEUE_NAME);
    print 'Job created' . PHP_EOL;
    sleep(1);
}

//worker.php

<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
require_once __DIR__ . '/vendor/autoload.php';

define("RABBITMQ_HOST", "localhost");
define("RABBITMQ_PORT", 5672);
define("RABBITMQ_USERNAME", "guest");
define("RABBITMQ_PASSWORD", "guest");
define("RABBITMQ_QUEUE_NAME", "task_queue");

$connection = new \PhpAmqpLib\Connection\AMQPStreamConnection(
    RABBITMQ_HOST,
    RABBITMQ_PORT,
    RABBITMQ_USERNAME,
    RABBITMQ_PASSWORD
);

$channel = $connection->channel();

# Create the queue if it doesnt already exist.
$channel->queue_declare(
    $queue = RABBITMQ_QUEUE_NAME,
    $passive = false,
    $durable = true,
    $exclusive = false,
    $auto_delete = false,
    $nowait = false,
    $arguments = null,
    $ticket = null
);


echo ' [*] Waiting for messages. To exit press CTRL+C', "\n";

$callback = function ($msg) {
    echo " [x] Received ", $msg->body, "\n";
    $job = json_decode($msg->body, $assocForm = true);
    sleep($job['sleep_period']);
    echo " [x] Done", "\n";
    $msg->delivery_info['channel']->basic_ack($msg->delivery_info['delivery_tag']);
};

$channel->basic_qos(null, 1, null);

$channel->basic_consume(
    $queue = RABBITMQ_QUEUE_NAME,
    $consumer_tag = '',
    $no_local = false,
    $no_ack = false,
    $exclusive = false,
    $nowait = false,
    $callback
);

while (count($channel->callbacks)) {
    $channel->wait();
}

$channel->close();
$connection->close();

Wzorzec observer

<?php

interface Subscriber
{
    public function send(): void;
}

class Client implements Subscriber
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function send(): void
    {
        echo 'i got it: ' . $this->name . '<br>';
    }
}

class Subject
{
    private $subscribers = [];

    public function subscribe(Subscriber $subscriber): void
    {
        $this->subscribers[] = $subscriber;
    }

    public function startWork(): void
    {
        sleep(1);
        //code

        foreach ($this->subscribers as $subscriber) {
            $subscriber->send();
        }
    }
}

$client1 = new Client('first client');
$client2 = new Client('second client');
$client3 = new Client('third client');

$subject = new Subject();

$subject->subscribe($client1);
$subject->subscribe($client2);
$subject->subscribe($client3);

$subject->startWork();

2)Implementacja Sedno wzorca Observer (obserwator) polega na rozdzieleniu elementów użytkujących (obserwatorów) od klasy centralnej (podmiotu obserwacji). Obserwatory muszą być informowane o zdarzeniach zachodzących w podmiocie obserwacji. Równocześnie nie chcemy wprowadzać trwałych i sztywnych zależności pomiędzy podmiotem obserwacji a klasami obserwatorów. Możemy więc umożliwić obserwatorom rejestrowanie się w klasie podmiotu. W tym celu powinniśmy uzupełnić klasę Login o trzy nowe metody: rejestracji (attach()), rezygnacji (detach()) i powiadomienia (notify()), przystosowując klasę do wymogów wyróżniających podmioty obserwacji interfejsu (tutaj ma on nazwę Observable):

<?php
interface Observable
{
    function attach(Observer $observer);
    function detach(Observer $observer);
    function notify();
}

<?php
// Klasa Login…
class Login implements Observable
{
    private $observers = array();
    private $storage;
    const LOGIN_USER_UNKNOWN = 1;
    const LOGIN_WRONG_PASS = 2;
    const LOGIN_ACCESS = 3;
    function attach(Observer $observer)
    {
        $this->observers[] = $observer;
    }
    function detach(Observer $observer)
    {
        $this->observers = array_filter($this->observers, function ($a) use ($observer)
        {
            return (!($a === $observer));
        });
    }
    function notify()
    {
        foreach ($this->observers as $obs)
        {
            $obs->update($this);
        }
    }
    
    //
    
}

Mamy więc klasę podmiotu utrzymującą listę obiektów obserwatorów. Obiekty te są dodawane do listy z zewnątrz poprzez wywołanie metody attach(). Rezygnacja z obserwacji i usunięcie z listy następuje w wyniku wywołania metody detach(). Z kolei wywołanie metody notify() służy jako powiadomienie obiektów obserwatorów o potencjalnie interesujących ich zdarzeniach. Implementacja tej metody sprowadza się do przejrzenia tablicy obiektów obserwatorów i wywołania na rzecz każdego z nich metody update(). Wywołanie metody rozsyłającej powiadomienia następuje we wnętrzu klasy Login, w ciele metody handleLogin():

//
function handleLogin($user, $pass, $ip)
{
    switch (rand(1, 3))
    {
        case 1:
            $this->setStatus(self::LOGIN_ACCESS, $user, $ip);
            $isvalid = true;
        break;
        case 2:
            $this->setStatus(self::LOGIN_WRONG_PASS, $user, $ip);
            $isvalid = false;
        break;
        case 3:
            $this->setStatus(self::LOGIN_USER_UNKNOWN, $user, $ip);
            $isvalid = false;
        break;
    }
    $this->notify();
    return $isvalid;
}

Zdefiniujmy interfejs klas obserwatorów:

interface Observer {
 function update(Observable $observable);
}

Do listy obserwatorów można dodawać (za pośrednictwem metody attach() klasy podmiotu obserwacji) dowolne obiekty, które implementują interfejs Observable. Tak wygląda tworzenie konkretnego egzemplarza:

<?php
class SecurityMonitor implements Observer
{
    function update(Observable $observable)
    {
        $status = $observable->getStatus();
        if ($status[0] == Login::LOGIN_WRONG_PASS)
        {
            // wyślij wiadomość do administratora…
            print __CLASS__ . "\twysyłam wiadomość do administratora\n";
        }
    }
}
$login = new Login();
$login->attach(new SecurityMonitor());

Zwróćmy uwagę, jak obiekt obserwatora odwołuje się do egzemplarza klasy Observable (podmiotu obserwacji) w celu pozyskania dodatkowych informacji o zdarzeniu. Metody, za pośrednictwem których obiekty obserwatorów mogłyby dowiadywać się o stanie, powinny zostać udostępnione właśnie w klasie podmiotu obserwacji. W tym przypadku klasa podmiotu ma zdefiniowaną metodę getStatus(), dzięki której obiekty obserwatorów mogą dowiadywać się o bieżącym stanie obiektu obserwowanego. Pojawia się tutaj pewien problem. Otóż w wywołaniu metody Login::getStatus() klasa SecurityMonitor bazuje na wiedzy o klasie Login, na której nie powinna polegać. Przecież w wywołaniu otrzymuje obiekt Observable, ale nie ma żadnej gwarancji, że będzie to właśnie obiekt Login. Mamy tu kilka możliwości: możemy rozszerzyć interfejs Observable tak, aby zawierał w sobie deklarację metody getStatus(), i możemy od razu przemianować interfejs na ObservableLogin, sygnalizując, że ma związek z klasami Login. Możemy też utrzymać ogólny interfejs Observable i obarczyć klasy Observable odpowiedzialnością za to, aby podmioty obserwacji były odpowiedniego typu. Możemy wtedy złożyć na nie również zadanie kojarzenia się z podmiotami obserwacji. Ponieważ będziemy mieć więcej niż jeden typ Observer, a zamierzamy zaimplementować przy okazji czynności porządkowe wspólne dla wszystkich podtypów, możemy od razu udostępnić abstrakcyjną klasę bazową:

<?php
abstract class LoginObserver implements Observer
{
    private $login;
    function __construct(Login $login)
    {
        $this->login = $login;
        $login->attach($this);
    }
    function update(Observable $observable)
    {
        if ($observable === $this->login)
        {
            $this->doUpdate($observable);
        }
    }
    abstract function doUpdate(Login $login);
}

Klasa LoginObserver wymaga do konstrukcji obiektu typu Login. W konstruktorze zachowuje sobie referencję obiektu i wywołuje własną metodę Login::attach(). W wywołaniu update() następuje sprawdzenie, czy przekazany obiekt Observable jest w istocie referencją obserwowanego podmiotu, po czym dochodzi do wywołania metody szablonowej doUpdate(). Teraz możemy utworzyć cały zestaw obiektów LoginObserver, z których każdy będzie operował na obiekcie Login, a nie na dowolnym obiekcie implementującym nasz stary interfejs Observable:

<?php
class SecurityMonitor extends LoginObserver
{
    function doUpdate(Login $login)
    {
        $status = $login->getStatus();
        if ($status[0] == Login::LOGIN_WRONG_PASS)
        {
            // wysłanie wiadomości do administratora
            print __CLASS__ . ":\twysyłam wiadomość do administratora\n";
        }
    }
}

class GeneralLogger extends LoginObserver
{
    function doUpdate(Login $login)
    {
        $status = $login->getStatus();
        // dodanie danych do rejestru
        print __CLASS__ . ":\tdodaję dane logowania do rejestru\n";
    }
}
class PartnershipTool extends LoginObserver
{
    function doUpdate(Login $login)
    {
        $status = $login->getStatus();
        // sprawdzenie adresu IP
        // ustawienie ciasteczka dla dopuszczonego IP
        print __CLASS__ . ":\tustawiam ciasteczko dla dopuszczonego IP\n";
    }
}
//Tworzenie i podłączanie obserwatorów LoginObserver jest teraz wykonywane w czasie konkretyzacji obiektów:
$login = new Login();
new SecurityMonitor($login);
new GeneralLogger($login);
new PartnershipTool($login);

 


Sortowanie po wielu kluczach

<?php

namespace DM\KategorieBundle\Service;

use DM\KategorieBundle\Entity\Kategorie;
use Doctrine\ORM\PersistentCollection;

class CategorySorter
{
    const TYPE_NORMAL = 1;
    const TYPE_TEMP = 2;
    const TYPE_WIN_BACK = 3;

    /**
     * sort categories by Type and name
     *
     * @param array $categories
     * 
     * @return array
     */
    public function sortCategoriesByTypeAndName(array $categories): array
    {
        $items = [];

        foreach ($categories as $singleCategory) {
            $type = self::TYPE_NORMAL;
            $nameWithHighlightedHtml = '<b>' . ($singleCategory['knad_nazwa'] ? $singleCategory['knad_nazwa'] . ' > ' : null) . $singleCategory['nazwa'] . '</b>' . ' [' . $singleCategory['id'] . ']';

            if ($singleCategory['temp'] === true && mb_strpos($singleCategory['nazwa'], 'win back', null, 'utf-8') !== false) {
                $type = self::TYPE_WIN_BACK;
                $nameWithHighlightedHtml = ($singleCategory['knad_nazwa'] ? $singleCategory['knad_nazwa'] . ' > ' : null) . $singleCategory['nazwa'] . ' [' . $singleCategory['id'] . ']' . ' <span class="label label-warning">win back</span> ';
            } else if ($singleCategory['temp'] === true) {
                $type = self::TYPE_TEMP;
                $nameWithHighlightedHtml = ($singleCategory['knad_nazwa'] ? $singleCategory['knad_nazwa'] . ' > ' : null) . $singleCategory['nazwa'] . ' [' . $singleCategory['id'] . ']' . ' <span class="label label-info">tymczasowa</span> ';
            }

            $name = ($singleCategory['knad_nazwa'] ? $singleCategory['knad_nazwa'] . ' > ' : null) . $singleCategory['nazwa'] . ' [' . $singleCategory['id'] . ']';

            $items[$singleCategory['id']] = [
                'name' => $name,
                'nameWithHighlightedHtml' => $nameWithHighlightedHtml . ($singleCategory['zarchiwizowany'] ? ' <span class="label label-danger">zarchiwizowana</span> ' : ''),
                'type' => $type,
                'id' => $singleCategory['id'],
                'archived' => $singleCategory['zarchiwizowany'],
            ];
        }

        usort($items, function ($a, $b) {
            if ($a['archived'] > $b['archived']) {
                return 1;
            } elseif ($a['archived'] < $b['archived']) {
                return -1;
            } else {

                if ($a['type'] > $b['type']) {
                    return 1;
                } elseif ($a['type'] < $b['type']) {
                    return -1;
                } else {
                    return strcmp(mb_strtolower($a['name'], 'UTF-8'), mb_strtolower($b['name'], 'UTF-8'));
                }
            }
        });

        return $items;
    }
    /**
     * sort categories collection by type and name to array
     *
     * @param array $categories
     * 
     * @return array
     */
    public function sortCategoriesCollectionByTypeAndNameToArray(PersistentCollection $categories): array
    {
        $categoriesArray = [];

        /** @var Kategorie $category */
        foreach ($categories as $category) {
            $categoriesArray[] = [
                'id' => $category->getId(),
                'nazwa' => $category->getNazwa(),
                'temp' => $category->getTemp(),
                'zarchiwizowany' => $category->getZarchiwizowany(),
                'knad_nazwa' => $category->getKategoriaNadrzedna() ? $category->getKategoriaNadrzedna()->getNazwa() : null
            ];
        }

        return $this->sortCategoriesByTypeAndName($categoriesArray);
    }
}

Funkcje php do parsowania xmla wydajność

<?php
//pamietaj o LIBXML_COMPACT | LIBXML_PARSEHUGE inaczej funkcje rzucają warringi przy dużych plikach

$xml = new \DOMDocument('1.0', 'utf-8');
$xml->loadXML($xmlData->asXML(), LIBXML_COMPACT | LIBXML_PARSEHUGE);
$xml->save($this->fileLocationPath);


$xml = simplexml_load_string(file_get_contents($this->fileLocationPath), 'SimpleXMLElement', LIBXML_COMPACT | LIBXML_PARSEHUGE);

Parsowanie stringa jak csv

$string = '
"Numer telefonu";"Dostarczono";"Data dostarczenia";"Powód odrzucenia";"Pobrano opłatę"\n
"500500500";"NIE";"";"";"TAK"';

$explode = explode('\n', $string);

$data = array_combine(str_getcsv($explode[0], ';'), str_getcsv($explode[1], ';'));

var_dump($data);

Łącznie kluczy z dwóch tablic

$array1 = [
  [
	  "ID" => "442505",
	  "Identyfikator użytkownika" => "748",
	  "Data utworzenia" => "10-01-2020 09:15:53",
	  "Data wysyłki" => "10-01-2020 09:15:53",
	  "Nadawca" => "Confronter",
	  "Treść" => "czesc",
	  "Wiadomości" => "1",
	  "Dostarczone" => "1",
	  "Koszt" => "1",
	  "Zwroty" => "0"
  ]
];

$array2 = [
	[
	  "ID wysyłki" => "442505",
	  "Numer telefonu" => "511152133",
	  "Dostarczono" => "TAK",
	  "Data dostarczenia" => "10-01-2020 09:15:59",
	  "Powód odrzucenia" => "",
	  "Pobrano opłatę" => "TAK"
	]
];

$newArray = return array_replace_recursive($array1, $array2);

//final
[
	[
	  "ID" => "442505"
	  "Identyfikator użytkownika" => "748"
	  "Data utworzenia" => "10-01-2020 09:15:53"
	  "Data wysyłki" => "10-01-2020 09:15:53"
	  "Nadawca" => "Confronter"
	  "Treść" => "czesc"
	  "Wiadomości" => "1"
	  "Dostarczone" => "1"
	  "Koszt" => "1"
	  "Zwroty" => "0"
	  "ID wysyłki" => "442505"
	  "Numer telefonu" => "511152133"
	  "Dostarczono" => "TAK"
	  "Data dostarczenia" => "10-01-2020 09:15:59"
	  "Powód odrzucenia" => ""
	  "Pobrano opłatę" => "TAK"
	]
]

Duże wielkie litery w windowsie

Na początku jako admin w poershellu:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

Nastpenie trzeba zainstalować dowolnego linuxa z strora. Potem znów w powershelu jako admin:

fsutil.exe file SetCaseSensitiveInfo C:\wamp64\www enable

Walidacja hasła

namespace App\Utils\User;

class PasswordValidator {

    /**
     * function is checking that password have at least uppercase 8 chars, special symbols etc.
     *
     * @param string $password
     * 
     * @return boolean
     */
    public function validate(string $password): bool {
        $uppercase = preg_match('@[A-Z]@', $password);
        $lowercase = preg_match('@[a-z]@', $password);
        $number = preg_match('@[0-9]@', $password);
        $specialChars = preg_match('@[^\w]@', $password);

        if (!$uppercase || !$lowercase || !$number || !$specialChars || mb_strlen($password, 'utf-8') < 8) {
            return false;
        }

        return true;
    }

}

soap php xml przykład

<?php

namespace DM\ApiBundle\Utils\ExternalApi\SmsTideSoftware;

use DM\ApiBundle\Utils\ExternalApi\ExternalApi;
use Symfony\Component\DependencyInjection\Container;
use SimpleXMLElement;
use DM\DashboardBundle\Utils\RandomCodeGenerator;

class SmsTideSoftwareApiAdapter extends ExternalApi {

    /**
     * max number of attempts
     */
    CONST MAX_NUMBER_OF_ATTEMPTS = 30;

    /**
     * delay check staus in seconds
     */
    CONST DELAY_CHECK_STATUS_IN_SECONDS = 1;

    /**
     * @var Container 
     */
    private $container;

    /**
     * @param Container $container
     */
    public function __construct(Container $container) {
        $this->normalizeInfo = '';
        $this->container = $container;
        $this->autorization();

        parent::__construct();
    }

    /**
     * autorization
     */
    private function autorization(): void {
        $host = $this->container->hasParameter('api_smsTideSoftwareConfronter_host') ? $this->container->getParameter('api_smsTideSoftwareConfronter_host') : '';
        $login = $this->container->hasParameter('api_smsTideSoftwareConfronter_login') ? $this->container->getParameter('api_smsTideSoftwareConfronter_login') : '';
        $pass = $this->container->hasParameter('api_smsTideSoftwareConfronter_pass') ? $this->container->getParameter('api_smsTideSoftwareConfronter_pass') : '';
        $key = $this->container->hasParameter('api_smsTideSoftwareConfronter_key') ? $this->container->getParameter('api_smsTideSoftwareConfronter_key') : '';
        $affiliateId = $this->container->hasParameter('api_smsTideSoftwareConfronter_affiliate_id') ? $this->container->getParameter('api_smsTideSoftwareConfronter_affiliate_id') : '';

        $this->setConnectionParameters($host, $login, $pass, $key, $affiliateId);
    }

    /**
     * call method 
     * 
     * @param type $method
     * @param type $parameters
     * @return array
     * 
     * @throws \Exception
     */
    public function call($method, $parameters = []): array {
        
    }

    /**
     * set normalize info
     * 
     * @param array $resposne
     * 
     * @return void
     */
    public function setNormalizeInfo($resposne): void {
        $arrayResult = json_decode(json_encode((array) $resposne), TRUE);

        if (isset($arrayResult['success'])) {
            $this->normalizeInfo .= $arrayResult['success'];
        }

        if (isset($arrayResult['error'])) {
            $this->normalizeInfo .= $arrayResult['error'];
        }
    }

    /**
     * set normalize status
     * 
     * @param type $resposne
     * 
     * @return void
     */
    public function setNormalizeStatus($resposne): void {
        $arrayResult = json_decode(json_encode((array) $resposne), TRUE);

        if (isset($arrayResult['success']) || isset($arrayResult['TideEnvelopeHeader']['TideCustomersID'])) {
            $this->normalizeStatus = self::STATUS_SUCCESS;
        }

        if (isset($arrayResult['error'])) {
            $this->normalizeStatus = self::STATUS_ERROR;
        }
    }

    /**
     * get sms report by external id or sms id 
     * 
     * @param int|null $externalID
     * @param int|null $smsId
     * 
     * @return array
     */
    public function getSmsReportByExternalIdOrSmsId(?int $externalID = null, ?int $smsId = null): array {
        $host = 'https://tideplatformgate.com/tidexmlreceiver/TideGate.asmx?WSDL';

        $content = '<?xml version="1.0" encoding="utf-8"?>
        <TideEnvelope:Envelope xmlns:Tide="http://www.tideplatformgate.com/TideProtocol.xsd" xmlns:TideEnvelope="http://www.w3.org/2003/05/soap-envelope">
            <TideEnvelope:Header>
                <Tide:CustomersID value="' . $this->login . '" />
                <Tide:UsersID value="' . $this->key . '" />
                <Tide:Password value="' . $this->pass . '" />
                <Tide:Generate Date="2019-11-26" Time="15:40:55.160" />
                <Tide:Receipt Date="2019-11-26" Time="15:40:55.160" />
            </TideEnvelope:Header>
            <TideEnvelope:Body>
                <Tide:Process id="1" actualnode="1">
                    <Tide:Node id="1" NodesID="23">
                        <Tide:Datagroup id="1" />
                        <Tide:Parameters>
                            <Tide:Parameter id="1" name="SMSStatusesDataGroup" value="1" />
                        </Tide:Parameters>
                    </Tide:Node>
                </Tide:Process>
                <Tide:Data>
                    <Tide:Group id="1">
                        <Tide:Items>';
        if ($externalID) {
            $content .= '<Tide:Item id="1" name="ExternalID">' . $externalID . '</Tide:Item>';
        }

        if ($smsId) {
            $content .= '<Tide:Item id="1" name="SMSID">' . $smsId . '</Tide:Item>';
        }

        $content .= '</Tide:Items>
                    </Tide:Group>
                </Tide:Data>
            </TideEnvelope:Body>
        </TideEnvelope:Envelope>';

        try {
            $resultXml = $this->callSoap($host, $content);
            $body = $resultXml->xpath('//TideEnvelopeEnvelope/TideEnvelopeBody/TideData/TideGroup/TideItems/TideItem/TideAttributes/TideAttribute');
            $arrayResult = json_decode(json_encode((array) $body), TRUE);

            return $arrayResult;
        } catch (\Exception $ex) {
            $this->normalizeStatus = self::STATUS_ERROR;
            $this->normalizeInfo .= 'error: ' . $ex->getMessage() . ' line: ' . $ex->getLine();
            return [];
        }
    }

    /**
     * sendSms
     * 
     * @param string $phoneNumber
     * @param string $senderName
     * @param string $content
     * 
     * @return void
     */
    public function sendSms(string $phoneNumber, string $senderName, string $content): void {
        $host = $this->affiliateId; //first free parametr from abstract !!! - because we have two hosts for this provider
        $randomNumber = time() . RandomCodeGenerator::generate(5);
        $content = '<?xml version="1.0" encoding="utf-8" ?>
            <TideEnvelope:Envelope xmlns:Tide="http://www.tideplatformgate.com/TideProtocol.xsd" xmlns:TideEnvelope="http://www.w3.org/2003/05/soap-envelope">
            <TideEnvelope:Header>
                <Tide:CustomersID value="' . $this->login . '" />
                <Tide:UsersID value="' . $this->key . '" />
                <Tide:Password value="' . $this->pass . '" />
            </TideEnvelope:Header>
            <TideEnvelope:Body>
                <Tide:Process id="1" actualnode="1">
                    <Tide:Node id="1" NodesID="23">
                        <Tide:Datagroup id="1" />
                        <Tide:Parameters>
                            <Tide:Parameter id="1" name="PhoneNumberAttributeClassID" value="1" />
                            <Tide:Parameter id="2" name="AuthorizationAttributeClassID" value="2" />
                            <Tide:Parameter id="3" name="ExternalIDAttributeClassID" value="3" />
                            <Tide:Parameter id="4" name="SuspensionAttributeClassID" value="4" />
                            <Tide:Parameter id="5" name="BrandingAttributeClassID" value="5" />
                            <Tide:Parameter id="6" name="PriorityAttributeClassID" value="6" />
                            <Tide:Parameter id="7" name="FlashAttributeClassID" value="7" />
                            <Tide:Parameter id="8" name="WAPAttributeClassID" value="8" />
                            <Tide:Parameter id="9" name="VoiceAttributeClassID" value="9" />
                            <Tide:Parameter id="10" name="TTSVoicesIDAttributeClassID" value="10" />
                            <Tide:Parameter id="11" name="SendDateTimeAttributeClassID" value="11" />
                        </Tide:Parameters>
                    </Tide:Node>
                </Tide:Process>
                <Tide:Data>
                    <Tide:Group id="1">
                        <Tide:Items>
                            <Tide:Item id="1" name="SMSMessage">' . $content . '</Tide:Item>
                            <Tide:Item id="2" name="SMSAttributes">
                                <Tide:Attributes save="1">
                                    <Tide:Attribute ExternalID="1" value="' . $phoneNumber . '" />
                                    <Tide:Attribute ExternalID="2" value="0" />
                                    <Tide:Attribute ExternalID="3" value="' . $randomNumber . '" />
                                    <Tide:Attribute ExternalID="5" value="' . $senderName . '"/>
                                    <Tide:Attribute ExternalID="6" value="0" />
                                    <Tide:Attribute ExternalID="7" value="0" />
                                    <Tide:Attribute ExternalID="8" value="0" />
                                    <Tide:Attribute ExternalID="9" value="0" />
                                </Tide:Attributes>
                            </Tide:Item>
                        </Tide:Items>
                    </Tide:Group>
                </Tide:Data>
            </TideEnvelope:Body>
        </TideEnvelope:Envelope>';

        $this->callSoap($host, $content);

        if ($this->normalizeStatus === self::STATUS_SUCCESS) {
            for ($i = 0; $i < self::MAX_NUMBER_OF_ATTEMPTS; $i++) {
                $smsData = $this->getSmsReportByExternalIdOrSmsId($randomNumber);
                if ($this->checkSmsStatus($smsData)) {
                    $this->normalizeStatus = self::STATUS_SUCCESS;
                    return;
                }

                sleep(self::DELAY_CHECK_STATUS_IN_SECONDS);
            }
        }

        $this->normalizeStatus = self::STATUS_ERROR;
        $this->normalizeInfo .= ' message could be not send';
    }

    /**
     * get report by year month and day
     * 
     * @param int $year
     * @param int $month
     * @param int|null $day
     * 
     * @return SimpleXMLElement
     */
    public function getReportByYearMonthAndDay(int $year, int $month, ?int $day = null): SimpleXMLElement {
        $content = '<?xml version="1.0" encoding="utf-8"?>
        <TideEnvelope:Envelope xmlns:Tide="http://www.tideplatformgate.com/TideProtocol.xsd" xmlns:TideEnvelope="http://www.w3.org/2003/05/soap-envelope">
            <TideEnvelope:Header>
                <Tide:CustomersID value="' . $this->login . '" />
                <Tide:UsersID value="' . $this->key . '" />
                <Tide:Password value="' . $this->pass . '" />
                <Tide:Generate Date="2009-11-26" Time="01:40:55.160" />
                <Tide:Receipt Date="2009-11-26" Time="01:40:55.160" />
            </TideEnvelope:Header>
            <TideEnvelope:Body>
                <Tide:Process id="1" actualnode="1">
                    <Tide:Node id="1" NodesID="29">
                        <Tide:Parameters>
                            <Tide:Parameter id="2" name="Year" value="' . $year . '" />
                            <Tide:Parameter id="3" name="Month" value="' . $month . '" />';
        if ($day) {
            $content .= '<Tide:Parameter id="4" name="Day" value="' . $day . '" />';
        }

        $content .= '</Tide:Parameters>
                    </Tide:Node>
                </Tide:Process>
            </TideEnvelope:Body>
        </TideEnvelope:Envelope>';

        return $this->callSoap($this->host, $content);
    }

    /**
     * check sms send status
     * 
     * @param array $result
     * 
     * @return bool
     */
    public function checkSmsStatus(array $result): bool {
        if (
                (isset($result[4]['@attributes']['name']) && $result[4]['@attributes']['name'] === 'DeliveryStatus') &&
                (isset($result[4]['@attributes']['value']) && $result[4]['@attributes']['value'] === '2')
        ) {
            return true;
        }

        return false;
    }

    /**
     * connect to web service
     * 
     * @param string $host
     * @param string $content - xml
     * 
     * @return SimpleXMLElement
     */
    public function callSoap(string $host, string $content): SimpleXMLElement {
        $optionsConnect = [
            'exceptions' => true,
            'trace' => 1,
            'cache_wsdl' => WSDL_CACHE_NONE,
            'connection_timeout' => 60, // in seconds
            'keep_alive' => false,
        ];

        try {
            $client = new \SoapClient($host, $optionsConnect);
            $contentXml = new SimpleXMLElement($content);
            $params = new \stdClass();
            $params->xml = $contentXml->asXML();
            $result = $client->PostXML($params);
            $response = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $result->PostXMLResult);
            if ($result->PostXMLResult === 'Authentication error') {
                throw new \Exception('Authentication error');
            }

            if (mb_strpos($result->PostXMLResult, 'OK ', null, 'utf-8') !== FALSE) {
                $response = '<?xml version="1.0" encoding="utf-8"?>
                <result>
                    <success>' . $response . '</success>
                </result>';
            }

            $result = new SimpleXMLElement($response);

            $this->setNormalizeInfo($result);
            $this->setNormalizeStatus($result);

            return $result;
        } catch (\Exception $ex) {
            $result = new SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?>
                <result>
                    <error>' . $ex->getMessage() . ' line: ' . $ex->getLine() . '</error>
                </result>');
            $this->setNormalizeInfo($result);
            $this->setNormalizeStatus($result);

            return $result;
        }
    }

}

Wzorzec mediator

<?php

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

interface Mediator {

    public function send(string $name, string $message): void;
}

class ConcreteMediator implements Mediator {

    private $colleagues = [];

    public function colleagueRegister(Colleague $colleague): void {
        $colleague->registerMediator($this);
        $this->colleagues[$colleague->getName()] = $colleague;
    }

    public function send(string $name, string $message): void {
        $this->colleagues[$name]->getMessage($message);
    }

}

class Colleague {

    private $mediator;
    private $name;

    public function __construct(string $name) {
        $this->name = $name;
    }

    public function registerMediator(Mediator $mediator): void {
        $this->mediator = $mediator;
    }

    public function getName() {
        return $this->name;
    }

    public function send(string $name, string $message): void {
        echo "Przesyłanie wiadomości od " . $this->name . " do " . $name . ": " . $message . '<br>';

        $this->mediator->send($name, $message); /// Rzeczywista komunikacja odbywa się za pośrednictwem mediatora!!!
    }

    public function getMessage(string $message): void {
        echo "Wiadomość odebrana przez " . $this->name . ": " . $message . '<br>';
    }

}

$michael = new Colleague("michael");
$john = new Colleague("john");
$lucy = new Colleague("lucy");


$mediator = new ConcreteMediator();
$mediator->colleagueRegister($michael);
$mediator->colleagueRegister($john);
$mediator->colleagueRegister($lucy);

$lucy->send('john', "Hello world.");

echo '<br>';

$michael->send('lucy', "Witaj!");
echo '<br>';


Stała dynamicznie pobrana z stringa

$test = constant(PhoneCheckNumber::class . "::" . 'STATUS_' . $stat3);

Usunięcie limitu pamięci w comoser

COMPOSER_MEMORY_LIMIT=-1 composer update

Wzorzec prototype

<?php
$timeStart = microtime(true);

function randomDateTime() {
    $timestamp = mt_rand(1, time());
    $randomDate = date("d M Y", $timestamp);
    return new DateTime($randomDate);
}

abstract class Solder {
    protected $name;
    protected $secondName;
    protected $rank = 'szeregowy';
    protected $uniformColor;
    protected $force;
    protected $flair;
    protected $courage;
    protected $life;
    protected $dateOfBirth;

//    public function __construct(string $name, string $secondName, string $uniformColor, int $force, int $flair, int $courage, int $life, DateTime $dateOfBirth) {
//        $this->name = $name;
//        $this->secondName = $secondName;
//        $this->uniformColor = $uniformColor;
//        $this->force = $force;
//        $this->flair = $flair;
//        $this->courage = $courage;
//        $this->life = $life;
//        $this->dateOfBirth = $dateOfBirth;
//    }

    public function getName() {
        return $this->name;
    }

    public function getSecondName() {
        return $this->secondName;
    }

    public function getRank() {
        return $this->rank;
    }

    public function getUniformColor() {
        return $this->uniformColor;
    }

    public function getForce() {
        return $this->force;
    }

    public function getFlair() {
        return $this->flair;
    }

    public function getCourage() {
        return $this->courage;
    }

    public function getLife() {
        return $this->life;
    }

    public function getDateOfBirth() {
        return $this->dateOfBirth;
    }

    public function setName($name) {
        $this->name = $name;
        return $this;
    }

    public function setSecondName($secondName) {
        $this->secondName = $secondName;
        return $this;
    }

    public function setRank($rank) {
        $this->rank = $rank;
        return $this;
    }

    public function setUniformColor($uniformColor) {
        $this->uniformColor = $uniformColor;
        return $this;
    }

    public function setForce($force) {
        $this->force = $force;
        return $this;
    }

    public function setFlair($flair) {
        $this->flair = $flair;
        return $this;
    }

    public function setCourage($courage) {
        $this->courage = $courage;
        return $this;
    }

    public function setLife($life) {
        $this->life = $life;
        return $this;
    }

    public function setDateOfBirth($dateOfBirth) {
        $this->dateOfBirth = $dateOfBirth;
        return $this;
    }

}

class StrongSolder extends Solder {
    protected $rank = 'general';
}

class CleverSolder extends Solder {
    
}

$strongSolder = (new StrongSolder())->setName('new janusz')->setSecondName('kowalsi')->setUniformColor('blul')->setForce(90)->setFlair(80)->setCourage(70)->setLife(49)->setDateOfBirth(randomDateTime());
$cleverSolder = (new CleverSolder())->setName('new jan')->setSecondName('kowalsi')->setUniformColor('blul')->setForce(90)->setFlair(80)->setCourage(70)->setLife(49)->setDateOfBirth(randomDateTime());

$strongSolders = [];
$cleversSolders = [];

for ($i = 0; $i < 10000; $i++) {
    $strongSolders[] = (new StrongSolder())
            ->setName('new janusz' . $i)
            ->setSecondName('kowalsi' . $i)
            ->setUniformColor('blul')
            ->setForce(90)
            ->setFlair(80)
            ->setCourage(70)
            ->setLife(49)
            ->setDateOfBirth(randomDateTime());

    $cleversSolders[] = (new CleverSolder())
            ->setName('new jan' . $i)
            ->setSecondName('kowalsi' . $i)
            ->setUniformColor('blul')
            ->setForce(90)
            ->setFlair(80)
            ->setCourage(70)
            ->setLife(49)
            ->setDateOfBirth(randomDateTime());
}

$timeEnd = microtime(true);
$executionTime = ($timeEnd - $timeStart);

echo '<h3><b>czas normalne tworzenie obiekto</b> ' . round($executionTime * 1000) . ' milliseconds</h3>';
echo '<h3><b>czas normalne tworzenie obiektow</b> ' . $executionTime . ' mikro</h3>';
echo '<h3><b>czas normalne tworzenie obiektow</b> ' . $executionTime/60 . ' sec</h3>';

$timeStart = microtime(true);

for ($i = 0; $i < 10000; $i++) {
    $strongSolders[] = clone $strongSolder
                    ->setName('new janusz' . $i)
                    ->setSecondName('kowalsi' . $i)
                    ->setUniformColor('blul')
                    ->setForce(90)
                    ->setFlair(80)
                    ->setCourage(70)
                    ->setLife(49)
                    ->setDateOfBirth(randomDateTime())
    ;
    $cleversSolders[] = clone $cleverSolder
                    ->setName('new jan' . $i)
                    ->setSecondName('kowalsi' . $i)
                    ->setUniformColor('blul')
                    ->setForce(90)
                    ->setFlair(80)
                    ->setCourage(70)
                    ->setLife(49)
                    ->setDateOfBirth(randomDateTime())
    ;
}
//printMemory();
//
//function printMemory() {
//    $mem_usage = memory_get_usage();
//    $mem_peak = memory_get_peak_usage();
//    echo 'The script is now using: <strong>' . round($mem_usage / 1024) . 'KB</strong> of memory.<br>';
//    echo 'Peak usage: <strong>' . round($mem_peak / 1024) . 'KB</strong> of memory.<br><br>';
//}
echo '<br><br>';
$timeEnd = microtime(true);
$executionTime = ($timeEnd - $timeStart);

echo '<h3><b>czas klonowanie</b> ' . round($executionTime * 1000) . ' milliseconds</h3>';
echo '<h3><b>czas klonowanie</b> ' . $executionTime . ' mikro</h3>';
echo '<h3><b>czas klonowanie</b> ' . $executionTime/60 . ' sec</h3>';

Czas wykonywania skryptu

<?php
$timeStart = microtime(true);
//code.....................

$timeEnd = microtime(true);
$executionTime = ($timeEnd - $timeStart);

echo '<h3><b>czas</b> ' . round($executionTime * 1000) . ' milliseconds</h3>';
echo '<h3><b>czas</b> ' . $executionTime . ' mikro</h3>';
echo '<h3><b>czas</b> ' . $executionTime/60 . ' sec</h3>';
<?php
$timeStart = microtime(true);
        
//code

$duration = $endtime - $timeStart;
$hours = (int)($duration/60/60);
$minutes = (int)($duration/60)-$hours*60;
$seconds = $duration-$hours*60*60-$minutes*60;
        
$milliseconds = round($duration * 1000);

echo '<h3><b>czas</b> ' . $milliseconds . ' milliseconds</h3>';
echo '<h3><b>czas</b> ' . number_format((float)$seconds, 2, '.', '') . ' seconds</h3>';
    protected function microtimeFormat($startTime, $format = null, $lng = null)
    {
        $seconds = microtime(true) - $startTime;
        $hours = ($seconds / 3600);
        $minutes = $seconds / 60;

        return [
            'hours' =>  number_format($hours, 4, '.', ''),
            'minutes' => number_format($minutes, 4, '.', ''),
            'seconds' => number_format($seconds, 4, '.', ''),
            'milliseconds' => $seconds * 1000
        ];
    }

Print memory php pamiec

function printMemory() {
    $mem_usage = memory_get_usage();
    $mem_peak = memory_get_peak_usage();
    echo 'The script is now using: <strong>' . round($mem_usage / 1024) . 'KB</strong> of memory.<br>';
    echo 'Peak usage: <strong>' . round($mem_peak / 1024) . 'KB</strong> of memory.<br><br>';
}

like w php

<?php
$expectedDateString = 'to słowo ma now w sobie';
if (mb_strpos($expectedDateString, 'now', null, 'utf-8') !== false) {
   echo 'jest';
}

Sms hosted api klasa

<?php

class SmsHostedApiAdapter extends ExternalApi {

    /**
     * send sms
     * 
     * @param string $phoneNumber
     * @param string $senderName - in this provider senderName is permanent
     * @param string $content - message content
     * 
     * @return string
     */
    public function sendSms(string $phoneNumber, string $senderName, string $content) {
        $transactionId = RandomCodeGenerator::generate(64, true);

        $parameters = [
            'Phone' => [$phoneNumber],
            'Message' => $content,
            'Sender' => $this->key,
            'TransactionId' => $transactionId,
            'Priority' => 1,
            'FlashSms' => false,
        ];

        return $this->sms_send($parameters);
    }

    /**
     * real method for send sms via api
     * 
     * @param array $params
     * @param string $token
     * 
     * @return string
     */
    private function sms_send(array $parameters) {
        return $this->call('Smses', $parameters, true);
    }

    /**
     * get delivery reports
     * 
     * @param array $parameters
     * 
     * @return type
     */
    public function getDeliveryReports(array $parameters) {
        return $this->call('DeliveryReports', $parameters, false);
    }

    /**
     * get inputs sms
     * 
     * @param array $parameters
     * 
     * @return type
     */
    public function getInputSms(array $parameters) {
        return $this->call('InputSmses', $parameters, false);
    }

    /**
     * call method 
     * 
     * @param type $method
     * @param type $parameters
     * @param bool $post - flag post or get method
     * @return array
     * 
     * @throws \Exception
     */
    public function call($method, $parameters = [], bool $post = true): array {
        $response = [];
        $url = $this->host . $method;

        if (!$post) {
            $parameters = http_build_query($parameters);
            $url .= '?' . $parameters;
        }

        $parameters = json_encode($parameters);

        $headers = [
            'Content-Type: application/json; charset=utf-8',
            'Accept: application/json',
            'Authorization: Basic ' . base64_encode("$this->login:$this->pass")
        ];

        try {
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            if ($post) {
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $parameters);
            }

            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

            $responseJson = curl_exec($ch);
            $response = json_decode($responseJson, true);

            $this->lastHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

            curl_close($ch);
        } catch (\Exception $ex) {
            throw new \Exception('Curl call failed! HttpCode: ' . $this->lastHttpCode . ' (Ex: ' . $ex->getMessage() . ')');
        }

        return $response;
    }

}

Klasa do wysyłki smsow

<?php

namespace App\Utils\ExternalApi\SmsApiAdapter;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;

class SmsApiAdapter {

    /**
     * @var Container 
     */
    private $container = null;

    /**
     * @var string 
     */
    private $token = null;

    /**
     * @param Container $container
     */
    public function __construct(Container $container) {
        $this->container = $container;
    }

    /**
     * authorization
     * 
     * @return void
     */
    public function authorization(): void {
        $this->token = $this->container->getParameter('sms_smsapi_token');
    }

    /**
     * send sms
     * 
     * @param string $phoneNumber - phone number
     * @param string $senderName - sender name
     * @param string $content - message content
     * 
     * @return mixed
     */
    public function sendSms(string $phoneNumber, string $senderName, string $content) {
        $params = array(
            'to' => $phoneNumber,
            'from' => $senderName,
            'message' => "" . $content . "",
        );

        return $this->sms_send($params, $this->token);
    }

    /**
     * send sms 
     * 
     * @param array $params
     * @param string $token
     * @param bool $backup
     * @return mixes
     * 
     * @throws \Exception
     */
    private function sms_send(array $params, string $token, bool $backup = false) {
        $result = null;

        if ($backup == true) {
            $url = 'https://api2.smsapi.pl/sms.do';
        } else {
            $url = 'https://api.smsapi.pl/sms.do';
        }

        $c = curl_init();
        curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($c, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($c, CURLOPT_URL, $url);
        curl_setopt($c, CURLOPT_POST, true);
        curl_setopt($c, CURLOPT_POSTFIELDS, $params);
        curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($c, CURLOPT_HTTPHEADER, array(
            "Authorization: Bearer $token"
        ));

        $result = curl_exec($c);
        $http_status = curl_getinfo($c, CURLINFO_HTTP_CODE);

        if ($http_status != 200 && $backup == false) {
            $backup = true;
            $this->sms_send($params, $token, $backup);
        }

        if (!(mb_strlen($result, 'utf-8') >= 2 && $result[0] == 'O' && $result[1] == 'K')) {
            throw new \Exception('SmsAPI - ' . $result);
        }

        curl_close($c);

        return $result;
    }

}

Normlaize polskich znaków

/**
 * Description of NormalizeNoneLatinCharacters
 *
 * @author Grzegorz Tarka
 */
class NormalizeNotPolishLetters {

    /**
     * normalize
     * 
     * @param string $string
     * 
     * @return string|null
     */
    public static function normalize(?string $string): ?string {

        $table = [
            'Š' => 'S', 'š' => 's', 'Đ' => 'Dj', 'đ' => 'dj', 'Ž' => 'Z', 'ž' => 'z', 'Č' => 'C', 'č' => 'c',
            'À' => 'A', 'Á' => 'A', 'Â' => 'A', 'Ã' => 'A', 'Ä' => 'A', 'Å' => 'A', 'Æ' => 'A', 'Ç' => 'C', 'È' => 'E', 'É' => 'E',
            'Ê' => 'E', 'Ë' => 'E', 'Ì' => 'I', 'Í' => 'I', 'Î' => 'I', 'Ï' => 'I', 'Ñ' => 'N', 'Ô' => 'O',
            'Õ' => 'O', 'Ö' => 'O', 'Ø' => 'O', 'Ù' => 'U', 'Ú' => 'U', 'Û' => 'U', 'Ü' => 'U', 'Ý' => 'Y', 'Þ' => 'B', 'ß' => 'Ss',
            'à' => 'a', 'á' => 'a', 'â' => 'a', 'ã' => 'a', 'ä' => 'a', 'å' => 'a', 'æ' => 'a', 'ç' => 'c', 'è' => 'e', 'é' => 'e',
            'ê' => 'e', 'ë' => 'e', 'ì' => 'i', 'í' => 'i', 'î' => 'i', 'ï' => 'i', 'ð' => 'o', 'ñ' => 'n',
            'ô' => 'o', 'õ' => 'o', 'ö' => 'o', 'ø' => 'o', 'ù' => 'u', 'ú' => 'u', 'û' => 'u', 'ý' => 'y', 'ý' => 'y', 'þ' => 'b',
            'ÿ' => 'y', 'Ŕ' => 'R', 'ŕ' => 'r', "ò" => 'ó', 'Ò' => 'Ó', 'ė' => 'e', 'Ė' => 'E'
        ];

        return strtr($string, $table);
    }

}

ustawienie ut8-8 w pdo

$connect = new PDO(
  "mysql:host=$host;dbname=$db", 
  $user, 
  $pass, 
  array(
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"
  )
);