Pull to refresh

Comments 33

Наверное глупый вопрос, но как устроен MyApplication::redirect($redirect_uri, $hash)?
Ведь пользователя надо отправить на биллинг методом POST
может как в openID редирект. Там тоже в коде пишется redirect, который рисует форму и отправляет ее постом при помощи явасрипта. Это считается рекомендованным способом в руководстве.
Но это как-то некошерно по-моему :)
может и не кошерно, но иного варианта нет :)
Прошу прощения, не совсем понял что «некошерного» в этом способе?
Не обязательно POST, в данном случае и GET допустим. Реализация редиректа зависит от фреймворка, например, MyApplication сохраняет данные, затем
1. Если нужен GET, MyApplication в самом финале вместо вывода страницы, посылает заголовки.
2. Если нужен POST, MyApplication выводит простенькую форму со скрытыми полями и видимой кнопкой submit и скрипт, сабмитящий эту форму при загрузке.
Кстати, почему MVC так не любите, раз уж про архитектуру речь зашла? Биллинг — какая-то странная смесь модели с контроллером, MyApplication — как минимум помесь контроллера с видом, неудобно же, запутаться можно.
Пример выдернут из системы, реализующий MVC. MyApplication — ядро движка. Контроллер там представлял ModuleBilling, View — вьювер, остальное со стороны модели. В данной статье хотелось сфокусироваться именно на реализации покупок и биллинга.
Ну я еще немножко попристаю?)

Конкретно, смущают строки:

$billing->redirectToBilling();
$billing->addResultInView($view, $result);
MyApplication::redirect($redirect_uri, $hash);

где модель берет на себя функции контроллера.

Насчет MyApplication выводы делал, исходя из «MyApplication выводит простенькую форму со скрытыми полями и видимой кнопкой submit и скрипт, сабмитящий эту форму при загрузке.» + то, что через него раздаются редиректы. То-ли это какая-то низкоуровневая библиотека, то-ли штука, которая знает даже как выводить аж js-скрипты для конкретного биллинга.
function actionBilling() как раз представитель контроллера (ModuleBilling это контроллер)

Насчёт MyApplication::redirect() правильнее сказать, результатом будет… Действия, приводящие к редиректу не обязательно полностью зашивать в MyApplication::redirect(). Можно установить соответствующиепараметры. Тогда в определённый момент $result сласса View Заменится на $result сласса HttpLocation с установленными параметрами, и $result->go() уже приведёт к нужному результату.

Конкретная реализация зависит от того, как принято редиректить в вашем фреймворке. Демонстрация таких подробностей в данном примере могла сделать его нечитабельным. Часть с коментарием "// где то там в системе:" вообще утрирована.
Понятно, что actionBilling() — это часть контроллера, но метод redirectToBilling — это ведь часть модели, и addResultInView — часть модели, и MyApplication::redirect вызывается в модели, вот откуда вопросы-то. А реализация редиректов в MVC-фреймворках такая: контроллер отдает код 302 или 301 в результате запроса, чего тут выдумывать-то) Понятно, что когда долго работаешь с какой-то системой, кажется, что все удобно и очевидно, но чего-то по этим всем косвенным признакам мне сейчас кажется, что в фреймворке каша все-таки (возможно, довольно несложно исправляемая).
Да, addResultInView — это компромиссный вариант, но очень удобный, поскульку так работа с биллингом собрана вся в одном месте. И потом тут нету непосредственно вывода, тут предоставление данных для вывода.

redirectToBilling в объекте биллинга не столько редиректит, сколько предоставляет для этого все необходимые данные.

Ваше предложение как это лучше раелизовать?
1. addResultInView — переименуйте и дергайте из вида или контроллера (лучше, наверное, из вида). Просто в MVC общение вида с моделью происходит в другом направлении — вид запрашивает данные у модели, а не наоборот.

2. С redirectToBilling все еще проще: вызывайте что-то вроде MyApplication::redirect($billing->redirectUrl()) в контроллере, пусть модель и в самом деле не редиректит, а только предоставляет данные.
Еще просьба к тому, кто делал интеграцию с cyberplat — прошу помощи. Существует ли способ интеграции на чистом PHP, без ихних корявых утилит?
Поскольку «ихние корявые утилиты» используются для цифровой подписи запросов, то нет, нельзя. Разве что Вы переведёте весь алгоритм подписи с C на PHP (они, вроде, дают исходники).
Чем-то напоминает паттерн «Мост» (Bridge) в терминологии Е. Гаммы — один из его вариантов.
Там, правда, обе части обычно более связаны, а у вас они больше логически относятся друг к другу, нежели физически, но тем не менее. Только диаграмму надо зеркально развернуть для большей ясности.
Да, напоминает. Ещё можно высмотреть что то похожее на паттерн Адаптер(Adapter) или Wrapper в каждой из частей. Но тоже не совсем то. Пожалуй я склоняюсь к тому, что в обеих частях используется полиморфизм в чистом виде.
Тоже сейчас реализую прием online-платежей, только сложность у меня не в большом количестве разных биллингов, а в большом количестве статусов покупок и сложной логике там (в разных местах программы разные действия в зависимости от статуса покупки, возможность оплачивать повторно, возможность отмены на некоторых этапах, обработка сбоев при подтверждении оплаты и т.д., но там задача не совсем стандартная, покупка в 2 этапа идет, а не в 1).

Очень помогает в этом State Pattern — для каждого состояния создается класс, и вся логика, зависящая от состояния (втч правильная смена состояния с обработкой возможных и невозможных переходов и уведомлениями), делегируется объектом «Покупка» экземпляру объекта «Состояние».
в смысле экземпляру класса «Состояние»
у Вас в названии топика в слове «Часть» пропущена буква «с».
Спасибо, сейчас поправлю
Хотел бы заметить следующие вещи:
— стоило бы сделать рисунок обычного движения информационных потоков, это реально помогло бы новичкам. Например, у вебмани в описании билинга сделано все очень понятно.
— я лично в биллинге перед тем, как отправлять пользователя на платежную систему, делаю страничку форму где все данные прописаны и две кнопки «Оплатить» «Отменить», так что Get и Post абсолютно не важны.
— если будет описание под конкретные платежные системы, готов поделиться имеющимся опытом
— Думаю временная диаграмма действительно уместна, постараюсь разместить в ближайшее время
— Насчёт: две кнопки «Оплатить» «Отменить». мне кажется важно зафиксировать у себя, что именно выбрал пользователь.
UFO just landed and posted this here
> Сразу оговорюсь, в другом языке, можно было обойтись абстрактным классом и его наследниками, но поскольку в PHP нельзя переопределить статическую функцию, предков разделили на интерфейс + базовый класс.

Это и сейчас можно, вот так, например, pastebin.ru/308744

В Вашем варианте можно сделать «class CPurchase implements InterfacePurchase» что позволит переложить проверку сигнатур методов на PHP.

Я один заметил, что при выполнении этот блок
> case self::PURCHASE_SHOP:$purchase = new CPurchaseShop();
> case PURCHASE_ACCOUNT: $purchase = new CPurchaseAccount();
> case PURCHASE_RAIT: $purchase = new CPurchaseRait();
> //…
> default: throw new ExceptionUnknownPurchaseType (__CLASS__);

работает совсем не так, как ожидается?
ага, изначально там был return, потому не было break :) сча поправлю
по pastebin.ru/308744:
" 1) сам элемент можно хранить в этом классе, передавать в конструктор "
непонятно зачем? на стадии создания итак известен товар. getItem нужен прежде всего при дальнейшей обработке, когда надо по номеру покупки, узнать что за товар был продан. При этом getItem() переопределённый для каждого типа, избавляет от ещё одного switch

«интересно, почему одновременно может быть только один? объект-товар»? "
_mPurchase — это часть CPurchase, которая занимается только сохранением и чтением инфы о покупке в БД. CPurchase — это поведение этой покупки. Можно было их объединить в один класс, но это потянуло бы описание работы с БД в этом примере. А так пример абстрагирован от способа хранения данных.

> непонятно зачем? на стадии создания итак известен товар. getItem нужен прежде всего при дальнейшей обработке, когда надо по номеру покупки, узнать что за товар был продан. При этом getItem() переопределённый для каждого типа, избавляет от ещё одного switch

У Вас:

Хотя бы за тем, чтобы разделить 2 класса CPurchaseItem и

Сейчас

блин… само отправилось :(

Предыдущий комментарий следует читать так:

> непонятно зачем? на стадии создания итак известен товар. getItem нужен прежде всего при дальнейшей обработке, когда надо по номеру покупки, узнать что за товар был продан. При этом getItem() переопределённый для каждого типа, избавляет от ещё одного switch

Хотя бы за тем, чтобы разделить классы CPurchaseItem и CPurchase. В вашем случае, возможно, действительно удобнее использовать текущую реализацию, но у себя я бы разделил эти 2 класса (CPurchase скорее всего реализовал бы в качестве фабрики, как это написано чуть ниже, в этом случае, получение CPurchaseItem в самой фабрике точно лишнее — не должна она знать о способе получения item-а).
«В Вашем варианте можно сделать «class CPurchase implements InterfacePurchase» что позволит переложить проверку сигнатур методов на PHP»
тут да, вот с Биллингами уже не получится. там интерфейс требует статичный метод, который нельзя сделать абстрактным и нельзя пререопределить :(
По CBilling (к CPurchase тоже можно отнести), возможно, лучшим решением будет сделать отдельную фабрику (не обязательно, но это облегчит понимание кода) для создания биллингов — BillingFactory — все методы этого класса будут статичными (BillingFactory::createBillingByType, BillingFactory::getBillingTypeByRequest и т.д.), в нем же можно реализовать метод для добавления новых биллингов, тогда отпадет необходимость при добавлении новых типов модифицировать код. Будет примерно так — pastebin.ru/308746

Интересен 3 вариант, т.к. можно будет упростить реализацию.
А можно вместо POST/GET параметров использовать WebServices?
Sign up to leave a comment.

Articles