Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ Thumbs.db
.vscode/
*.sublime-project
*.local
*.log
*.log

node_modules

dist
13 changes: 13 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,19 @@ services:
networks:
- bitrix-net

node:
image: node:25-alpine
container_name: ${COMPOSE_PROJECT_NAME}_node
volumes:
- ./www:/var/www/html
working_dir: /var/www/html/local/js
command: tail -f /dev/null
user: "1000:1000"
ports:
- "5173:5173"
networks:
- bitrix-net

networks:
bitrix-net:
driver: bridge
Expand Down
4 changes: 2 additions & 2 deletions www/.htaccess
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ ErrorDocument 404 /404.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-d
#RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
#RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
RewriteCond %{REQUEST_FILENAME} !/bitrix/urlrewrite.php$
RewriteRule ^(.*)$ /bitrix/urlrewrite.php [L]
RewriteCond %{REQUEST_FILENAME} !/bitrix/routing_index.php$
RewriteRule ^(.*)$ /bitrix/routing_index.php [L]
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
Expand Down
2 changes: 1 addition & 1 deletion www/.php-cs-fixer.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"php":"8.4.15","version":"3.91.3:v3.91.3#9f10aa6390cea91da175ea608880e942d7c0226e","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":false,"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"no_unused_imports":true},"hashes":{"local\/php_interface\/init.php":"a78eac41d9d56df178d44973467f45c6","local\/tests\/ExampleTest.php":"fc073181fd099491844a38da814ec086","local\/php_interface\/tests_bootstrap.php":"2dbff910839ac81ecad37f4e33e092be","local\/php_interface\/phpstan_bootstrap.php":"6f9fd8a908d1fda7dcc3694bc9d4ed00","local\/php_interface\/phpstan_globals.php":"2d9b39aae3b76b29cc9a373cbd74638b","local\/test_d7.php":"3c824fefaf8fcf06e42add8db36e74f6"}}
{"php":"8.4.15","version":"3.91.3:v3.91.3#9f10aa6390cea91da175ea608880e942d7c0226e","indent":" ","lineEnding":"\n","rules":{"binary_operator_spaces":{"default":"at_least_single_space"},"blank_line_after_opening_tag":true,"blank_line_between_import_groups":true,"blank_lines_before_namespace":true,"braces_position":{"allow_single_line_empty_anonymous_classes":true},"class_definition":{"inline_constructor_arguments":false,"space_before_parenthesis":true},"compact_nullable_type_declaration":true,"declare_equal_normalize":true,"lowercase_cast":true,"lowercase_static_reference":true,"modifier_keywords":true,"new_with_parentheses":{"anonymous_class":true},"no_blank_lines_after_class_opening":true,"no_extra_blank_lines":{"tokens":["use"]},"no_leading_import_slash":true,"no_whitespace_in_blank_line":true,"ordered_class_elements":{"order":["use_trait"]},"ordered_imports":{"imports_order":["class","function","const"],"sort_algorithm":"none"},"return_type_declaration":true,"short_scalar_cast":true,"single_import_per_statement":{"group_to_single_imports":false},"single_space_around_construct":{"constructs_followed_by_a_single_space":["abstract","as","case","catch","class","const_import","do","else","elseif","final","finally","for","foreach","function","function_import","if","insteadof","interface","namespace","new","private","protected","public","static","switch","trait","try","use","use_lambda","while"],"constructs_preceded_by_a_single_space":["as","else","elseif","use_lambda"]},"single_trait_insert_per_statement":true,"ternary_operator_spaces":true,"unary_operator_spaces":{"only_dec_inc":true},"blank_line_after_namespace":true,"constant_case":true,"control_structure_braces":true,"control_structure_continuation_position":true,"elseif":true,"function_declaration":{"closure_fn_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"after_heredoc":false,"attribute_placement":"ignore","on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_multiple_statements_per_line":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_line_after_imports":true,"spaces_inside_parentheses":true,"statement_indentation":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"encoding":true,"full_opening_tag":true,"array_syntax":{"syntax":"short"},"no_unused_imports":true},"hashes":{"local\/php_interface\/init.php":"abd7527e503c9e91320b5621abe33ceb","local\/tests\/ExampleTest.php":"fc073181fd099491844a38da814ec086","local\/php_interface\/tests_bootstrap.php":"2dbff910839ac81ecad37f4e33e092be","local\/php_interface\/phpstan_bootstrap.php":"6f9fd8a908d1fda7dcc3694bc9d4ed00","local\/php_interface\/phpstan_globals.php":"2d9b39aae3b76b29cc9a373cbd74638b","local\/test_d7.php":"f7ea5707d50a294b4ad274be9b69b3a1","local\/classes\/Local\/Model\/RequestTable.php":"f566fd734def2b3cade319c680c8a3ac","local\/classes\/Local\/Agents\/NewsAgent.php":"dace8c39412f3d3f05f09bb7bd283fe5","local\/classes\/Local\/MessageHandler\/SendWebhookHandler.php":"da20b41fd115edb81f867bee33023a6d","local\/classes\/Local\/Service\/BusFactory.php":"92d03df444560093b9ac25c365892306","local\/classes\/Local\/Service\/NotificationService.php":"93845a9fdeb2f7a2a6fb085b81a4ac3d","local\/classes\/Local\/Service\/RequestService.php":"d0b433673c88c4650c1c03c32af58d38","local\/classes\/Local\/Events\/LogsElementAdd.php":"802fc804cb01dee63669dc22332c986d","local\/classes\/Local\/Events\/RequestEventHandler.php":"b3e9a442fb93796319071a1ea0535788","local\/classes\/Local\/Message\/SendWebhook.php":"58270df79d5046e9d03371c750abdf95","local\/classes\/Local\/DTO\/RequestDTO.php":"0924060ba80ee29e5a40aa03a7bef922","local\/components\/local\/api.news.list\/class.php":"93a77b33788b774b65425e7da962a7fd","local\/modules\/my.api\/install\/index.php":"897e2da4c13cea38cb7864f27ecd2fb9","local\/modules\/my.api\/lib\/controller\/requestcontroller.php":"4773bb8b3026c9edf9710eb2b7ce0aa3","local\/routes\/api.php":"5f4d3d3c50f0c25cd95a854c4cf600c9","local\/test_orm_custom.php":"edbd315ff83988dbba8f87a248fc35b1","local\/test_orm.php":"d485e8ad9f036dc2ca1e9b54b5045fb2","local\/bin\/Worker.php":"cbb8c7bc82c5bf985e74fa9f8ed85361","local\/php_interface\/migrations\/HighLoadTable20251209212051.php":"b5dec77bb1baed6c9c0c262c7bdbdec2","local\/php_interface\/migrations\/Version20251206225809.php":"38b7695aafb555f74c67fd7b61d249b4","local\/php_interface\/migrations\/Version20251206230244.php":"2fc2a201605041f245ebf435fe02f58e"}}
2 changes: 1 addition & 1 deletion www/.phpunit.result.cache
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":2,"defects":{"ExampleTest::testUserAdminExists":7},"times":{"ExampleTest::testBitrixIsLoaded":0.001,"ExampleTest::testUserAdminExists":0.066}}
{"version":2,"defects":{"ExampleTest::testUserAdminExists":7,"RequestServiceTest::testCreateRequestSavesDataAndReturnsId":7},"times":{"ExampleTest::testBitrixIsLoaded":0.008,"ExampleTest::testUserAdminExists":0.011,"RequestServiceTest::testCreateRequestSavesDataAndReturnsId":0.002}}
6 changes: 3 additions & 3 deletions www/local/bin/Worker.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<?php

define('NO_KEEP_STATISTIC', true);
define('NOT_CHECK_PERMISSIONS',true);
define('NOT_CHECK_PERMISSIONS', true);
define('CHK_EVENT', true);

$_SERVER["DOCUMENT_ROOT"] = realpath(__DIR__ . '/../../');
Expand All @@ -24,10 +24,10 @@
[$bus, $transport] = BusFactory::create();

$worker = new Worker(
['default' => $transport],
['default' => $transport],
$bus
);

$worker->run([
'sleep' => 1000,
]);
]);
9 changes: 6 additions & 3 deletions www/local/classes/Local/Agents/NewsAgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

class NewsAgent
{
public static function deactivateOldNews() {
if (!Loader::IncludeModule('iblock')) return;
public static function deactivateOldNews()
{
if (!Loader::IncludeModule('iblock')) {
return;
}

$date = new DateTime();
$date->add('-30 day');
Expand All @@ -36,4 +39,4 @@ public static function deactivateOldNews() {

return "\Local\Agents\NewsAgent::deactivateOldNews();";
}
}
}
24 changes: 24 additions & 0 deletions www/local/classes/Local/DTO/BasketDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
declare(strict_types=1);

namespace Local\DTO;

readonly class BasketDTO implements \JsonSerializable
{
public function __construct(
public float $totalPrice,
public string $totalPriceFormatted,
public int $totalCount,
public array $items
) {}

public function jsonSerialize(): array
{
return [
'totalPrice' => $this->totalPrice,
'totalPriceFormatted' => $this->totalPriceFormatted,
'totalCount' => $this->totalCount,
'items' => $this->items,
];
}
}
36 changes: 36 additions & 0 deletions www/local/classes/Local/DTO/BasketItemDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);

namespace Local\DTO;

readonly class BasketItemDTO implements \JsonSerializable
{
public function __construct(
public int $id,
public int $productId,
public string $name,
public float $price,
public string $formattedPrice,
public float $sum,
public string $formattedSum,
public int $quantity,
public ?string $image = null,
public string $detailUrl = ''
) {}

public function jsonSerialize(): array
{
return [
'id' => $this->id,
'productId' => $this->productId,
'name' => $this->name,
'price' => $this->price,
'formattedPrice' => $this->formattedPrice,
'sum' => $this->sum,
'formattedSum' => $this->formattedSum,
'quantity' => $this->quantity,
'image' => $this->image,
'detailUrl' => $this->detailUrl,
];
}
}
19 changes: 19 additions & 0 deletions www/local/classes/Local/DTO/OrderCreateDTO.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php
declare(strict_types=1);

namespace Local\DTO;

readonly class OrderCreateDTO
{
public function __construct(
public int $userId,
public string $siteId,
public int $personTypeId,
public int $deliveryServiceId,
public int $paySystemId,
public array $items,
public array $properties,
public ?string $comment = null,
public string $currency = 'RUB',
) {}
}
2 changes: 1 addition & 1 deletion www/local/classes/Local/DTO/RequestDTO.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ public function __construct(
throw new \InvalidArgumentException('Phone cannot be empty');
}
}
}
}
8 changes: 4 additions & 4 deletions www/local/classes/Local/Events/LogsElementAdd.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

namespace Local\Events;

use Bitrix\Main\EventManager;
use Bitrix\Main\Diag\FileLogger;
use Bitrix\Main\Application;

const NEWS_IBLOCK_ID = 1;

class LogsElementAdd
{
public static function handleNews(&$fields) {
public static function handleNews(&$fields)
{
if (empty($fields['ID'])) {
return;
}
Expand All @@ -30,7 +30,7 @@ public static function handleNews(&$fields) {
$logger = new FileLogger($fullPath);

$date = date('Y-m-d H:i:s');

$message = sprintf(
"[%s] Добавлена новость: %s (ID: %d)" . PHP_EOL,
$date,
Expand All @@ -40,4 +40,4 @@ public static function handleNews(&$fields) {

$logger->info($message);
}
}
}
6 changes: 2 additions & 4 deletions www/local/classes/Local/Events/RequestEventHandler.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
<?php

declare(strict_types=1);

namespace Local\Events;

use Bitrix\Main\Event;
use Bitrix\Main\Diag\FileLogger;
use Bitrix\Main\Application;
use Local\Service\NotificationService;
use Local\Message\SendWebhook;
use Local\Service\BusFactory;

Expand All @@ -27,4 +25,4 @@ public static function onAdd(Event $event)

$bus->dispatch($message);
}
}
}
6 changes: 4 additions & 2 deletions www/local/classes/Local/Message/SendWebhook.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php

declare(strict_types=1);

namespace Local\Message;
Expand All @@ -7,5 +8,6 @@ class SendWebhook
{
public function __construct(
public int $requestId
) {}
}
) {
}
}
4 changes: 2 additions & 2 deletions www/local/classes/Local/MessageHandler/SendWebhookHandler.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<?php

declare(strict_types=1);

namespace Local\MessageHandler;

use Local\Message\SendWebhook;
use Local\Service\NotificationService;
use Bitrix\Main\Loader;
use Local\Model\RequestTable;

class SendWebhookHandler
Expand Down Expand Up @@ -46,4 +46,4 @@ public function __invoke(SendWebhook $message)
echo "CRITICAL ERROR: " . $e->getMessage() . "\n";
}
}
}
}
17 changes: 15 additions & 2 deletions www/local/classes/Local/Model/RequestTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields;
use Bitrix\Main\ORM\Fields\Relations\Reference;
use Bitrix\Main\ORM\Query\Join;
use Bitrix\Main\UserTable;
use Bitrix\Main\ORM\Fields\Validators\RegExpValidator;
use Bitrix\Main\Type\DateTime;
use Bitrix\Main\Localization\Loc;
Expand All @@ -25,6 +28,16 @@ public static function getMap()
->configureAutocomplete(true)
->configureTitle('ID'),

(new Fields\IntegerField('USER_ID'))
->configureNullable(true)
->configureTitle('ID Пользователя'),

(new Reference(
'MY_USER',
UserTable::class,
Join::on('this.USER_ID', 'ref.ID')
))->configureJoinType(Join::TYPE_LEFT),

(new Fields\StringField('USER_NAME'))
->configureRequired(true)
->configureTitle('Имя пользователя'),
Expand All @@ -41,10 +54,10 @@ public static function getMap()
->configureTitle('Комментарий'),

(new Fields\DatetimeField('CREATED_AT'))
->configureDefaultValue(function() {
->configureDefaultValue(function () {
return new DateTime();
})
->configureTitle('Дата создания'),
];
}
}
}
78 changes: 78 additions & 0 deletions www/local/classes/Local/Repository/RequestRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Local\Repository;

use Local\Model\RequestTable;
use Local\DTO\RequestDTO;

use Bitrix\Main\ArgumentException;
use Bitrix\Main\ObjectPropertyException;
use Bitrix\Main\SystemException;
use Bitrix\Main\Event;
use Exception;

class RequestRepository implements RequestRepositoryInterface
{
public function save(RequestDTO $requestDTO): int
{
$result = RequestTable::add([
'USER_NAME' => $requestDTO->name,
'PHONE' => $requestDTO->phone,
'COMMENT' => $requestDTO->comment . ' from repository' ?? '',
]);

if (!$result->isSuccess()) {
throw new \Exception(implode(', ', $result->getErrorMessages()));
}

return $result->getId();
}

public function findById(int $id): ?array
{
try {
$row = RequestTable::getByPrimary($id)->fetch();

return $row === false ? null : $row;
} catch (ObjectPropertyException|ArgumentException|SystemException $e) {
return null;
}
}

public function getAll(): ?array
{
$queryResult = RequestTable::getList([
'select' => [
'ID',
'USER_NAME',
'USER_ID',
'USER_LOGIN' => 'MY_USER.LOGIN',
'USER_EMAIL' => 'MY_USER.EMAIL'
],
'order' => ['ID' => 'DESC'],
]);

$result = [];

while ($row = $queryResult->fetch()) {

$item = [
'id' => (int)$row['ID'],
'user_name' => $row['USER_NAME'],
'auth_info' => null,
];

if ((int)$row['USER_ID'] > 0) {
$item['auth_info'] = [
'id' => (int)$row['USER_ID'],
'login' => $row['USER_LOGIN'],
'email' => $row['USER_EMAIL'],
];
}

$result[] = $item;
}

return $result;
}
}
Loading