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.
- 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
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
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"
)
);