Проектирование и разработка веб-приложения на основе технологий Symfony Framework
История развития веб-технологий и существующие проблемы. Назначение и установка Symfony Framework. Создание приложения на основе технологий Symfony Framework. Установка дополнительных библиотек через composer, верстка шаблона, настройка сервисов.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 05.07.2017 |
Размер файла | 712,6 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
После создания класса сущности В Symfony имеется возможность создания объекта формы, а затем его отображение в шаблоне.
<?
namespace AppBundle\Controller;
use AppBundle\Entity\Task;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
classDefaultControllerextends Controller
{
publicfunctionnewAction(Request $request)
{
// Создание объекта сущности
$task = newTask();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
// Генерацияформы
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, array('label' =>'Create Post'))
->getForm();
//Отображениешаблона
return $this->render('default/new.html.twig', array(
'form' => $form->createView(),
));
}
}
Листинг 12. Создание объекта формы
Создание формы требует относительно небольшого кода, потому что объекты формы Symfony построены с помощью «конструктора форм». Задача создателя формы - написать простой генератор формы, форма сгенерируется автоматически.
В примере на листинге 12 добавлено два поля в форму - task и dueDate - соответствующие свойствам taskи dueDateсвойствам Task класса. Так же назначается каждому свойству «тип» (например, TextTypeи DateType), представленный его полным именем класса. Помимо прочего, он определяет, какой HTML-тег отображается для этого поля.Также добавляется кнопка отправки с пользовательской надписью для отправки формы на сервер.
Когда форма была создана, следующим шагом будет ее рендеринг. Это делается путем передачи объекта формы «view» в шаблон и с помощью набора вспомогательных функций формы. Для отображения полной формы необходимы три строки в Twig:
· form_start(form)
Отображает начальный тег формы, включая атрибут enctype при использовании загрузки файлов.
· form_widget(form)
Отображает все поля, включая сам элемент поля, метку и любые сообщения об ошибках проверки для поля.
· form_end(form)
Отображает конечный тег формы и любые поля, которые еще не были отображены, если была произведена ручная визуализация каждого поля. Это полезно для визуализации скрытых полей и использования автоматической защиты CSRF.
По умолчанию форма отправит POST запрос обратно на тот же контроллер, который отображает её. Для обработки полученных данных используется код, указанный в листинге 13.
// ОтправкавформуобъектаRequest
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// Получениеданныхизформы
$task = $form->getData();
// Сохранение полученных данных в базе
$em->persist($task);
$em->flush();
return $this->redirectToRoute('task_success');
}
Листинг 13. Получение и обработка данных из формы
В Symfony валидация применяется к базовому объекту. Другими словами, вопрос заключается не в том, является ли «форма» валидной, а является ли объект валидным после того, как форма применила к нему предоставленные данные. Вызов $form->isValid()- это сокращение, которое запрашивает у объекта, имеет ли он валидные данные.
Проверка выполняется путем добавления в класс сущности набора правил (называемых ограничениями). Это может быть реализовано, как с помощью аннотация, так и файлов YAML, XMLи PHP. Валидация производится с помощью классов внутри пространства имён Symfony\Component\Validator\Constraints. Доступные ограничения:
Основные ограничения
· NotBlank
· Blank
· NotNull
· IsNull
· IsTrue
· IsFalse
· Type
Строковые ограничения
· Length
· Url
· Regex
· Ip
· Uuid
Числовые ограничения
· Range
Сравнительные ограничения
· EqualTo
· NotEqualTo
· IdenticalTo
· NotIdenticalTo
· LessThan
· LessThanOrEqual
· GreaterThan
· GreaterThanOrEqual
Ограничения по дате
· Date
· DateTime
· Time
Ограничения коллекции
· Choice
· Collection
· Count
· UniqueEntity
· Language
· Locale
· Country
Файловые ограничения
· File
· Image
Финансовые и числовые ограничения
· Bic
· CardScheme
· Currency
· Luhn
· Iban
· Isbn
· Issn
Другие ограничения
· Callback
· Expression
· All
· UserPassword
· Valid
При выводе формы имеется возможность добавления атрибутов для валидации формы средствами HTML 5, указания типов полей (textarea, email, money, url, password, choice, date, file и т. д.), надписи. При отсутствии фактического указания этих параметров, Symfonyпытается «угадать» их значение. Если это происходит некорректно, необходимо вручную переопределить данные параметры.
Symfonyпредоставляет возможность создания формы в отдельном автономном PHP-классе, который затем может быть повторно использован в любом месте приложения. По умолчанию такие классы располагаются в директории Formбандла и могут быть использованы в контроллерах.
1.5.8 Безопасность
Организация безопасности в Symfonyпроисходит в три этапа:
1. Первоначальная настройка security.yml(аутентификация);
2. Запрет доступа к приложению (авторизация);
3. Получение текущего объекта пользователя.
Система безопасности настраивается в файле app/config/security.yml. Конфигурация по умолчанию представлена в листинге 14.
security:
providers:
in_memory:
memory: ~
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
anonymous: ~
Листинг 14. Конфигурация безопасности по умолчанию
В данном файле определяются все настройки безопасности приложения. Например, ссылка, на которую будет перенаправлен пользователь при попытке входа на защищённую страницу, ссылка на страницу выхода, разрешение анонимного пользователя, параметры кодирования пароля и т. д.
На следующем этапе в параметре access_controlуказывается список защищённых маршрутов и права доступа к ним, а в параметре role_hierarchy категории групп прав, иерархия ролей.
Одним из основных параметров является «users», который определяет, каким образом будет задана информация о пользователях (непосредственно из файла или конкретной сущности).Внутри контроллера и шаблона имеется возможность проверить права текущего пользователя, проверить, является ли он авторизованным,и, в зависимости от этого, выполнять различные действия.
Symfonyпредоставляет возможность создания собственных обработчиков событий при возникновении различных событий связанных с безопасностью (авторизация, выход, регистрация, ввод неверного пароля и т. д.)
1.5.9 Сервисы
SymfonyFrameworkнаполнен полезными объектами: объект «Mailer» помогает отправлять электронные письма, а другой объект может помочь сохранить данные в базе данных. Почти все, что делает приложение фактически выполняется одним из этих объектов. При установке нового бандла увеличивается количество доступных объектов.
В Symfony эти объекты называются сервисами, и каждый сервис находится внутри особого объекта, называемого контейнером сервисов. После получения контейнера сервисов, можно получить сервис, используя идентификатор эго сервиса с помощью метода get(): «$logger = $container->get('logger');»
Контейнер позволяет централизовать способ конструирования объектов. Для получения полного списка доступных сервисов из контейнера необходимо ввести консольную команду: «php bin/console debug:container».
Собственные сервисы по умолчанию располагаются в папке Serviceв каталоге бандла. После его создания необходимо зарегистрировать сервис в конфигурационном файле. При необходимости использования другого сервиса внутри текущего, в конструкторе сервиса указывается аргумент с типом необходимого сервиса, что также нужно указать в файле конфигурации.
При запросе сервиса, контейнер создает новый объект и возвращает его. Но если сервис не был запрошен, он никогда не будет сконструирован.Это экономит память и скорость. Он также создается только один раз: один и тот же экземпляр возвращается каждый раз, когда запрашивается.
1.5.10 Консольные команды
Symfony Framework предоставляет множество команд через bin/consoleскрипт (например,команда bin/console cache:clear). Эти команды создаются с помощью компонента Console. Он так же используется для создания пользовательских команд.
Команды определяются в классах, которые должны быть созданы в директории Command бандла (например, AppBundle\Command), и их имена должны заканчиватьсясуффиксом Command.
Внутри данных классов имеется возможность получения сервисов из контейнера, добавление аргументов (методом addArgument), вывод в консоль (методом writeln), определения названия (setName), описания (setDescription) и помощи (setHelp) по команде.
Команды имеют три метода жизненного цикла, которые вызываются при выполнении команды:
initialize() (необязательный)
Этот метод выполняется до interact() и execute() методов. Его основная цель - инициализировать переменные, используемые в остальных командных методах.
interact() (необязательный)
Этот метод выполняется после initialize() и до execute(). Его цель - проверить, отсутствуют ли некоторые из параметров / аргументов и интерактивно спросить у пользователя эти значения. Это последнее место, где можно запросить отсутствующие параметры / аргументы. После этой команды отсутствующие параметры / аргументы приведут к ошибке.
execute() (обязательный)
Этот метод выполняется после interact() и initialize(). Он содержит логику, которую необходимость выполнить.
1.5.11. Механизмы тестирования
Symfony интегрируется с независимой библиотекой, называемой PHPUnit. Каждый тест - будь то unit-тест или функциональный тест - это класс PHP, который должен находиться в каталоге tests/ бандла.PHPunit конфигурируется в файле phpunit.xml.dist в корне проекта Symfony. Unit-тест (модульный тест) - это тест для одного класса PHP, также называемого unit. Написание модульных тестов Symfony ничем не отличается от написания стандартных модульных тестов PHPUnit. Как правило таким тестам подвергаются классы низкого уровня. Это означает, что контроллеры и сервисы, обладающие большим количеством зависимостей сложно поддаются модульному тестированию, так как основная его идея - проверка конкретных методов и участков кода на соответствие ожидаемым значениям. В листинге 15 приведёт простейший класс и пример возможного тестирования с помощью PHPUnit. Для запуска всех тестов в проекте используется консольная команда «phpunit». Функциональные тесты проверяют интеграцию различных уровней приложения (от маршрутизации до представления). Они ничем не отличаются от модульных тестов, так как используют PHPUnit, но они имеют специфический рабочий процесс:
· Создать запрос;
· Проверить ответ;
· Нажать ссылку или отправить форму;
· Проверить ответ;
· Повторить.
Функциональные тесты - это простые PHP-файлы, которые обычно располагаются в tests/AppBundle/Controller каталоге бандла. Например, длятестирования страниц, обрабатываемых PostControllerклассом, создаётся новый PostControllerTest.php файл, который расширяет специальный WebTestCaseкласс. Пример такого теста представлен в листинге 16.
// src/AppBundle/Util/Calculator.php
namespace AppBundle\Util;
classCalculator
{
publicfunctionadd($a, $b)
{
return $a + $b;
}
}
// tests/AppBundle/Util/CalculatorTest.php
namespace Tests\AppBundle\Util;
use AppBundle\Util\Calculator;
use PHPUnit\Framework\TestCase;
classCalculatorTestextends TestCase
{
publicfunctiontestAdd()
{
$calc = new Calculator();
$result = $calc->add(30, 12);
// Отображает, что тест пройден успешно
$this->assertEquals(42, $result);
}
}
Листинг 15. Примерописанияunit-теста
<?
// tests/AppBundle/Controller/PostControllerTest.php
namespace Tests\AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
classPostControllerTestextends WebTestCase
{
publicfunctiontestShowPost()
{
//Создаётклиента
$client = static::createClient();
// Создаётget-запроскстранице /post/hello-world
$crawler = $client->request('GET', '/post/hello-world');
// При наличие на странице текста «HelloWorld» тест считается успешно пройденным
$this->assertGreaterThan(
0,
$crawler->filter('html:contains("Hello World")')->count()
);
}
}
Листинг 16. Пример функционального теста
Для запуска функциональных тестовкласс WebTestCaseзагружает ядро ??приложения. При тестировании данным способом доступно множество методов для имитации поведения реального пользователя, такие как нажатие на кнопку или ссылку, отправка формы, загрузка файлов и т. д. Основной идей такого тестирования является поиск соответствий фактического поведения приложения с ожидаемым. Это достигается путём полной эмуляции работы ядра Symfony, вместе со всеми её сервисами, эмуляции клиента, а также сравнения статусов ответа, HTML-тегов, атрибутов форм, перехода по ссылкам с ожидаемыми (правильными).
1.6 Развертывание приложенияSymfony
Развертывание приложения Symfony может быть сложной и разнообразной задачей в зависимости от настроек и требований приложения.
Типичные шаги для развертывании приложения Symfony, включают:
· Загрузка кода на рабочий сервер;
· Установка зависимостей (обычно это выполняется через Composer и может быть выполнено перед загрузкой);
· Выполнение миграции базы данных или аналогичных задач для обновления любых измененных структур данных;
· Очистка кеша.
Развертывание может также включать другие задачи, такие как:
· Пометка определенной версии кода как релиза в системе контроля версиями;
· Создание временного промежуточногоокружения для создания обновленной настройки «offline»;
· Выполнение любых тестов для обеспечения стабильности кода и / или сервера;
· Удаление ненужных файлов из web/каталога, для очисткиproduction-среды;
· Очистка внешних систем кэширования (например, Memcached или Redis).
Существует несколько способов развертывания приложения Symfony. Начните с нескольких основных стратегий развертывания и создайте оттуда.
Самый простой способ развертывания приложения - копирование файлов вручную через FTP / SCP (или аналогичный метод). У этого есть свои недостатки, поскольку отсутствует система версионирования при дальнейшем обновлении. Этот метод также требует выполнить некоторые шаги вручную после передачи файлов.
При использовании системы контроля версий (например, Git или SVN), необходима её поддержка на стороне сервера, а также выполнение дополнительных действий, после копирования файлов из версионного контроля.
Существуют также инструменты, помогающие облегчить процесс развертывании. Некоторые из них были специально адаптированы к требованиям Symfony.
· Capistrano с плагином Symfony
Capistrano - это средство автоматизации и развертывания удаленного сервера, написанное на Ruby. Плагин Symfony - это плагин для облегчения задач, связанных с Symfony.
· sf2debpkg
Помогает создать пакет Debian для проекта Symfony.
· Magallanes
Это инструмент развертывания, подобный Capistrano, построен на PHP.
· Fabric
Эта библиотека на основе Python предоставляет базовый набор операций для выполнения локальных или удаленных shell-команд и выгрузки / загрузки файлов.
После развертывания исходного кода необходимо сделать несколько общих вещей:
a) Проверить соответствие системным требования с помощью «php bin/symfony_requirements»
b) Настроить app/config/parameters.yml файл
c) Установить / обновитьбиблиотекиспомощьюкоманды «composer install --no-dev --optimize-autoloader»
d) Очиститькэш Symfony командой «php bin/console cache:clear --env=prod --no-debug --no-warmup»
f) Дополнительно, в зависимости от конфигурации, могут потребоваться дополнительные вещи:
· Выполнение миграций баз данных
· Очистка кэша APC
· Запуск assets:install
· Добавление / редактирования заданий CRON
· Публикация frontend-зависимостей в CDN
· Запуск тестов
· Контроль качества
После всех выполненных действий веб-приложение готово к работе и использованию на удалённом сервере.
Глава 2. Создание приложения на основе технологий Symfony Framework
2.1 Постановка задачи
Основным преимуществом Symfony Framework является сочетание комплекса современных подходов в области веб-проектирования: соответствие кода современным стандартам, структурирование, поддержку и масштабируемость, реализацию ООП-подхода при описании структуры и функционала, сокращение времени разработки, возможность повторно использовать модули.
В рамках выпускной квалификационной работы была определена практическая задача - реализациявеб-приложения на основе технологий SymfonyFrameworkс учётом современных подходов в области проектирования, разработки, оформления, тестирования программного продукта. Актуальным и популярным сервисом в области веб можно считать типовой интернет-магазин, к которому в современных условиях предъявляются следующие требования:
· масштабируемость и универсальность структуры данных и функционала;
· стандартизация кода;
· сокращение времени на обработку запросов, загрузки страниц;
· устойчивость к высоким нагрузкам;
· эргономичность использования программного продукта, как для разработчика, так и целевой пользовательской аудитории;
· обеспечение безопасности хранимых и передаваемых данных;
· организация обратной связи с пользователем.
На основе анализа технологий SymfonyFramework, приведённого в главе 1, в качестве программной реализации возможностей его компонентов и подходов был реализован интернет-магазин, демонстрирующий типовой процесс разработки веб-приложения, отвечающего вышеприведённым требованиям.
2.2 Настройка develop-сервера и установка Symfony
В качестве операционной системы, используемой при написании проекта была выбрана Ubuntu 16.04 с предустановленным PHP7.0, который необходим для корректного функционирования многих бандлов Symfony. После обновления системы PHPбыл обновлён до версии 7.1, а также были произведены следующие настройки PHP:
· Включено расширение JSON
· Включено расширение ctype
· В php.ini указан date.timezone
· Установлен модуль PHP-XML
· Установлен модуль libxml
· Установлен модуль PHP-GD
· Включена функция mbstring
· Установлены и включены модули PDO и PDO_PGSQL
· А также изменены настройки php.ini
o short_open_tag = On
o magic_quotes_gpc = Off
o register_globals = Off
o session.auto_start = Off
Далее была установлена СУБД PostgreSQLс помощью команды в терминале Ubuntu«sudo apt-get install postgresql postgresql-client», а также сконфигурирована и создана база данных «symfony_game_shop» с помощью команд, представленных в листинге 16.
su - postgres
psql
CREATE USER root WITH PASSWORD 'root';
CREATE DATABASE symfony_game_shop;
GRANT ALL PRIVILEGES ON DATABASE symfony_game_shopto root;
\q
Листинг 16.Создание базы данных «symfony_game_shop»
Также были выполнены следующие команды в терминале:
· aptinstallcomposer (установка менеджера зависимостей composer)
· aptinstallnodejs(установка менеджера зависимостей NPM)
· npm install --global webpack@1.12.11 (установкасборщикаfrontend webpack)
· npminstall --globalbower(установка менеджера зависимостей bower)
· composerglobalrequirefriendsofphp/php-cs-fixer (установкаприложения для приведения кода к современным стандартам)
· composerglobalrequirephpunit/phpunit(установкаприложения для тестирования приложения)
· echo 'exportPATH="$PATH:$HOME/.composer/vendor/bin"' >> ~/.bashrc (добавлениеприложенийcomposerв глобальную область видимости)
· source ~/.bashrc (применение изменений в файле ~/.bashrc)
Установка Symfonyбыла произведена с помощью SymfonyPluginдляIDEPhpStorm, которая также обладает рядом возможностей для удобства разработки (подсветка синтаксиса, характерного только для Symfony, поддержка шаблонизатора Twig, ORMDoctrine, помощь при генерации форм и т. д.)
После установки были удалены файлы, связанные со стандартным базовым бандлом, установлена система контроля версий Git, а файлы проекта включены в версионный контроль, с учётом содержимого файла .gitignore (см. приложениеA).
+---app/
¦ +---Resources/ - шаблоны сторонних бандлов
¦ +---config/ - основные файлы конфигурации приложения
¦L---...
+---assets/
¦ L---src/ - файлы frontendдля сборки
+---bin/ - исполняемые файлы
+---src/ - PHPкод проекта
¦ L---Difuks/
¦ L---DazzleBundle/ - основной бандл
¦+---Admin/ -классы конфигурации административной панели
¦+---Command/ - классы консольных команд
¦ +---Controller/ - контроллеры
¦+---Entity/ - сущности
¦+---EventHandler/ - обработчики событий
¦+---Extension/- расширения библиотек
¦+---Form/ - классы форм
¦+---Repository/ - репозитории сущностей
¦ +---Resources/
¦¦+---config/ - конфигурационные файлы бандла
¦¦L---views/ - шаблоны Twig
¦+---Services/ - сервисы
¦L---Tests/- тесты
+---var/ - кеш, логики и прочие сгенерированные файлы
+---web/- корневой каталог веб-сайта
L---... - конфигурационные файлы composer, npm, webpack, phpunit, php-cs, .gitignore
Листинг 17. Структура каталога файлов frontend
Все файлы, связанные с основным функционалом приложения сосредоточены в директории src/DiFuks/DazzleBundle, за исключениям основных конфигурационных фалов и файлов, связанных с frontend. Общая файловая структура проекта представлена в листинге 17.
2.3 Установка дополнительных библиотек через composer
В процессе разработки приложения были установлены следующие библиотеки, путём добавление информации о них в конфигурационный файл composer.json:
· friendsofsymfony/user-bundle - добавляет поддержку системы пользователей с поддержкой базы данных в Symfony. Он обеспечивает гибкую структуру для управления пользователями, которая направлена на решение общих задач, таких как регистрация пользователей с подтверждением, сброс пароля, хранения и управление пользователями с помощью Doctrine[22].
· gregwar/image-bundle - предоставляетуправлениеизображениями и API для Symfony и Twig.
· league/color-extractor - извлекает цвета из изображений и сортирует их по частоте использования.
· sonata-project/admin-bundle - добавляет возможности для генерации и управления административной панелью[24].
· sonata-project/doctrine-orm-admin-bundle-интегрирует sonata-project/admin-bundle сORM Doctrine.
Дляустановкивсехиспользуемыхбиблиотекиспользоваласькоманда «composerinstall», адляустановкиfronted-зависимостей sonata-project/admin-bundle команды «bower install ./vendor/sonata-project/admin-bundle/bower.json» и «php bin/console assets:install web/assets».
2.4 Вёрсткашаблона, npm, webpack
В качестве менеджера frontend-зависимостей был использован npm. В файле package.json (см. приложениеA)был сформирован список библиотек, используемых при вёрстке шаблона. В качестве css-фреймворка выбран «materialdesignlight», предоставляющийосновные компоненты вёрстки элементов в стиле materialdesign, а также реализующий её адаптивность. Возможность использовать такие возможности, как написание стилей на языке less, использование синтаксиса ECMAScript6 (классы в JavaScript, импорт / экспорт модулей и т. д.) реализуют библиотеки npmпод названием babel, less-loader, file-loader, webpack, css-loader.
Для осуществления жёсткого разграничения между frontendи backend, а также для преобразования lessв css и приведения js-файлов к поддерживаемому устаревшими браузерами виду,был использован сборщик frontendwebpack, а также организована файловая структура, которая отделяет все файлы стилей, изображения и скрипты от основного backend-функционала приложения.Webpackбыл установлен через менеджер зависимостей npmи сконфигурирован с учётом доступных библиотек и модулей.
В процессе вёрстки шаблона была использована методология БЭМ (Блок, Элемент, Модификатор), которая позволяет создавать расширяемые и повторно используемые компоненты интерфейса [24]. Все файлы стилей, скрипты, изображения, шрифты хранятся в папке assets/src/директории проекта.
Таким образом, для каждого маршрута средствами webpackпри загрузки страницы подключаются четыре файла - общие файлы cssи js, а также используемые только в этом маршрутеcssи js, определяемые точкой входа. Сгенерированные файлы располагаются в директории web/assets/build/ и исключены из версионного контроля.
+---blocks/ - содержит отдельные повторно используемые блоки
¦ +---basket/ - содержит js-код и стили для виджета корзины
¦ ¦ +---basket.js
¦ ¦L---basket.less
¦ +---feedback/ - содержит js-код и стили для виджета обратной связи
¦ ¦ +---feedback.js
¦ ¦L---feedback.less
¦ L---...- содержит блоки для других виджетов на сайте
+---img/- содержит изображения
¦ +---icons/
¦ ¦ +---...
¦ L---logo.png
+---modules/ - содержит скрипты и стили, используемые во всём сайте или в различных блоках
¦ L---...
+---admin_common.js - точка входа для страниц административной панели
+---basket.js - точка входа для страницы корзины
+---catalog.js - точка входа для страницы каталога товаров
+---common.js - точка входа, общая для всех публичных страниц
L---... - точки входа для других страниц
Листинг 18. Структура каталога файлов frontend
В директории src/Difuks/DazzleBundle/Resources/views/ содержатся шаблоны twig-базовые шаблоны публичной части сайта, административной панели, email-сообщения; шаблоны компонентов административной панели, вижетов, страниц публичной части и различные почтовые шаблоны.
2.5 Генерация сущностей и форм
База данных была спроектирована таким образом, чтобы отобразить различные типы связей (один ко многим, многие к одному, многие ко многим), использовать различные типы данных, правила валидации и разнообразные возможности ORMDoctrine.
Для реализации поставленной задачи был создан набор сущностей. Все поля и их типы указаны на рисунке 7. Для каждого свойства (за исключением ID) созданы методы для получения и изменения значения (геттеры и сеттеры). Связи между сущностями реализованы с помощью объектно-реляционной модели PostgreSQL, их типы так же указаны на рисунке 7. В некоторых сущностях используется свойство «code», являющееся уникальным, и валидируемое по регулярному выражению - оно должно содержать только символы латиницы, символы «-, _» и цифры. Это поле используется для формирования человекопонятных url.
· Key - ключи игр для добавления в корзину. Содержит вспомогательный метод для получения статуса ключа на основе связанной корзины.
· Game - игры. Содержит вспомогательные методы для получения списка не купленных ключей, обновления рейтинга на основе добавленного отзыва, получения рейтинга в целочисленном формате, получения цены с учётом скидки, определения добавлена ли игра в «избранное» для конкретного пользователя, получения количества отзывов.
· News - новости сайта.
· User - пользователи.
· Genre - жанры игр.
· Image - изображения, используемыевсущностяхGame (логотип, скриншоты), News, Genre, Settings.
Рис. 7. Схема реализуемой базы данных
Basket - корзина пользователя. Содержит вспомогательные методы для получения текущей стоимости корзины с учётом скидок, фактической стоимости после покупки игр с учётом скидок и без, получения количества игр в корзине, добавления и изменения количества игр и ключей в связанной сущности BasketProduct, получения количества конкретной игры, удаления ключей из корзине по определённой игре.
· Review - отзывы об игре.
· Discount - скидки.
· Feedback - обратная связь.
· Settings - настройкисайта.
· Developer - разработчики игр.
· Publisher - издатели игр.
· NewsReview - отзывы о новостях.
· SiteReview - отзывы о сайте.
· Subscribes - подписки на новости сайта.
· BasketProduct - товары корзины (игра и её количество). Содержит вспомогательный метод для определения стоимости с учётом скидки
ВприложенииBпредставленасущностьGameввидеклассаDoctrine. Генерация сущностей осуществлялась с помощью консольной командыSymfony, а также доработана вручную с учётом реализации необходимых связей, методов и правил валидации.
Помимо самих сущностей были созданы три репозитория, упрощающие процесс выполнения специфичных запросов данных:
· GameRepository - содержит методы для получения общего количества игр в базе данных, максимальной цены, минимальной цены с учётом скидок, минимального и максимального допустимого возраста, игр со скидкой, а также метод для выборки игр по фильтру. Данный репозиторий представлен в приложении C.
· BasketRepository - содержит методы для получения корзины по текущему пользователю, и выборки «старых» корзин.
· BasketProductRepository - содержит метод, переопределяющий базовый метод findAll, с целью изменения направления сортировки (повозрастанию ID).
На основе некоторых сущностей были созданы классы для генерации пользовательских форм, а именно: форма обратной связи (представлена вместе с сущностью Feedbackв приложении D), форма изменения данных пользователя и форма регистрации.
2.6 Определение маршрутов и контроллеров
Конфигурация маршрутов разделена на три части, а классы контроллеров на четыре по их предназначению, каждая группа маршрутов обладает собственным префиксом. Также в основном файле конфигурации маршрутизации подключаются файлы настроек маршрутов для бандла аутентификации пользователей и административной панели.
Были выделены следующие группы маршрутов и контроллеров:
· Public. Маршруты обладают префиксом «/»и определяют доступ к страницам публичной части сайта. Контроллер отвечает за простое отображения страниц. Код конфигурации данной группы маршрутов и обрабатывающий их класс контроллера представлен в приложении E.
· Ajax. Маршруты обладают префиксом «/ajax/» и определяет доступ через Ajax. Контроллер за изменение каких-либо данных модели и, в некоторых случаях отображения виджетов в качестве результата этих изменений.
· Widget. Маршрутов не содержит. Контроллер отвечает за отображение часто используемых встраиваемых элементов интерфейса (виджетов).
· Order. Маршруты обладают префиксом «order». Контроллер отвечает за обработку запросов со стороны стороннего сервиса оплаты и внесение результатов этих запросов в модель.
2.7 Создание и настройка сервисов
Сервисы были разделены на три категории по их назначению:
· EventHandler - обработчики событий.
· Extension - расширения сторонних сервисов.
· Services - сервисы в привычном понимании Symfony.
Обработчики событий представлены двумя классами:
· AuthenticationHandler - содержит методы для обработки события успешного входа и ошибки авторизации.
· FlushHandler - содержит методы для обработки события обновления данных в БД, а именно для рассылки почты при перехода игры в статус «выпущена» и добавлении новости.
Расширения представлены классами, добавляющие возможность использовать функцию Roundв запросах DQL, а также добавляющие функции getJs (получает jsпо имени маршрута), getCss(получает cssпо имени маршрута)и file_exists (стандартная функции определения существования файла в PHP) в шаблонизатор Twigдля более удобной интеграции с frontend.
Сервисы представлены двумя классами:
· OrderService (представлен в приложении F) -осуществляет интеграцию с системой оплаты «Робокасса» [25].Содержит методы для формирование url, используемого для перехода в систему оплаты, обработки результата запроса от службы оплаты, отправки emailоб успешной оплате, обновления количества покупок игры и даты последней покупки, обработки запроса на странице завершения оплаты, получения текущей корзины пользователя, добавления необходимого количества игр в корзину, изменения количества находящейся в корзине игры, удаления игры из корзины, удаления старых корзин.
· SocialService - содержит методы для добавления игры в избранное, emailв список подписок, отзыва об игре, сообщения обратной связи, отписки от новостей.
После создания собственных сервисов и добавления сторонних, их необходимо настроить. Были созданы классы (в директории src/Difuks/DazzleBundle/Admin/), определяющие и структурирующие отображение сущностей в административной панели. Отправка почты настроена таким образом, что email, требующие немедленной отправки (уведомление о регистрации, смены пароля и т. д.) отсылаются моментально, а остальные (отправка новости, уведомление о выходе игры) сохраняются в специальный файл и могут быть отправлены только после выполнения специальной консольной команды (для защиты от блокировки за спам-рассылку). Собственные сервисы определены и настроены в соответствии с требуемыми зависимостями. Файл настроек собственных сервисов представлен в приложении F.
2.8 Написание консольных команд и заданий cron
В процессе создания приложения возникла потребность реализации функционала очистки заброшенных корзин, так как количество ключей в реализуемом магазине ограничено, а при добавлении игры в корзину ключ резервируется и становится недоступным для попки другими пользователями.
В предыдущих пунктах были реализованы методы для удаления таких корзин. Но чтобы это удаление происходило не вручную, а автоматически была реализована консольная команда, удаляющая корзины, ожидающие оплаты (по умолчанию старее трёх суток), а также неоплаченные корзины (по умолчанию одни сутки). Программный код данной команды представлен в приложении G. После ввода «phpbin/console difuks:dazzle:basket:clear-old» заброшенные корзины, если они существуют, удаляются, а в консоли выводится количество удалённых корзин. Тем не менее, данный процесс всё ещё не автоматизирован. Для того, чтобы команда выполнялась автоматически, необходимо добавит её в задания cron[26]. Для систем Debian (в данном случае Ubuntu) это реализуется командой в терминале: «echo "0 0 * * * root cd /path/to/project/ && bin/console difuks:dazzle:basket:clear-old >> var/logs/cron.log" >> /etc/crontab». После ввода данной команды очистка заброшенных корзин будет производиться каждые сутки в 00:00 по серверному времени.
Также необходимо автоматизировать отправку почты, сохранённой во временный файл и ожидающей отправки с помощью команды в терминале «echo "0 * * * * root cd /path/to/project/ && bin/console swiftmailer:spool:send --message-limit=5 --env=prod >> var/logs/cron.log" >> /etc/crontab». Отправка почты будет производится каждый час по 5 emailмаксимум. Это гарантирует защиту от блокировки за рассылку спама.
2.9 Тестирование
Тестирование осуществлялось с помощью встроенных механизмов Symfony, расширяющих возможности PHPUnit [27]. Были реализованы функциональные тесты, осуществляющие проверку корректности выполнения основных функций реализуемого веб-приложения, а именно:
· Корректное осуществление авторизации;
· Корректная деавторизация;
· Корректный статус ответа всех страниц публичной части;
· Осуществление перенаправления неавторизованного пользователя на страницу авторизации при попытке входа в административную панель, а также на страницу корзины; корректное отображения этих страниц для авторизованного пользователя;
· Корректное осуществление добавления игры в корзину (существование хотя бы одной доступной для покупки игры, невозможность покупки неавторизованному пользователю).
Программный код последнего из указанных тестов и конфигурация PHPUnitпредставлена в приложении G. Для запуска тестов необходимо выполнить команду: «phpunit», находясь в корневой директории проекта. В случае неуспешного прохождения какого-либо из тестов в консоли отобразиться описание ошибки и дополнительная информация по ней.
2.10 Перенос проекта на production-сервер
Перенос проекта на production-сервер состоял из следующих этапов:
· Приведения всего программного кода к стандартам Symfony (расширение стандартов PSR-2) с помощью утилиты php-cs-fixer [28].
· Отправка всех изменений на сервере разработки в систему контроля версий.
· Аренда виртуального сервера на хостинге FirstVDS. Характеристики арендованного сервера: Процессор Intel Xeon 2,4 ГГц (1 ядро), оперативная память 1ГБ, диск HDD+SSD 30 ГБ, операционная система Ubuntu 16.04.
· Регистрация домена difk.ruи изменение серверов имённа серверы имён FirstVDS для доступа к серверу по адресу.
· Подключение по sshк удалённому серверу.
· УстановкаPHP 7.1, PostgreSQL, git, composer, npm, webpack, bower, phpunit.
· Настройка PHP, создание базы данных PostgreSQL(процесс аналогичен таковому на сервере разработки).
· Клонирования репозитория из системы контроля версий.
· Установка зависимостей composer, npm, bower. Запусксборщикаwebpackдляproduction-среды (NODE_ENV=productionwebpack).
· Миграция базы данных.
· Запуск тестов PHPUnit.
· Добавление заданий cron.
· Настройка виртуального хоста apache2 (для доступа из сети по адресу difk.ruк папке webприложения).
· Перезапуск apache2.
После всех выполненных действий веб-приложение Symfonyготово к работе и доступно по адресу http://difk.ru.
Заключение
Современный этап развития технологий в области веб-проектирования предоставляет возможности для разрешения проблем, являющихся актуальными и глобальными. В ходе выполнения выпускной квалификационной работы были поставлены и решены следующие задачи.
В ходе анализасуществующих современных технологий и моделей в области веб были обозначены проблемы в области веб-разработки и приведены некоторые типовые решения, способствующие устранению обозначенных проблем и противоречий. В качестве методологии в области веб-проектирования был обозначен шаблон проектирования MVC, реализующий ООП-подход в области веб.
Технологии SymfonyFrameworkотвечают современным требованиям и стандартам, поддерживают шаблон проектирования MVC, обеспечивают безопасность доступа к данным, увеличивают быстродействие запросов, обладают высоким уровнем масштабируемости. Основные компоненты SymfonyFramework: бандлы, Doctrine, маршрутизация, контроллеры, шаблонизатор Twig, сервисы и т.д. - предоставляют инструментарий для разработки сложно структурируемых веб-приложений в соответствии с принятыми стандартами в области веб. Отсутствие официальной русскоязычной документации по SymfonyFramework поставило дополнительную задачу по адаптации официальной документации разработчика на русский язык.
На основе анализа моделей и подходов в области веб, инструментария и функционала SymfonyFramework в качестве демонстрации программной реализации возможностей его компонентов и подходов был реализован интернет-магазин, иллюстрирующий типовой процесс разработки веб-приложения, отвечающего современным требованиям. В работе большое внимание было уделено техническим вопросам по настройке и развертыванию проекта на production-сервере.
Для разработанного приложения были написаны функциональные автоматизированные тесты, на основании которых осуществлено тестирование приложения.
Таким образом цель выпускной квалификационной работы - выполнить анализ возможностей технологий Symfony Framework и реализовать приложение интернет-магазина компьютерных игр на основе современных подходов в области веб-разработки - была достигнута.
Результаты выпускной квалификационной работы могут быть использованы как теоретическое пособие по SymfonyFramework, а практическая разработка - в качестве модели проектирования и реализации веб-приложения. При соответствующей адаптации к предметной области приложение может быть использовано как полноценный интернет-магазин.
Список литературы
1. History of the Web. URL: http://webfoundation.org/about/vision/history-of-the-web/ (датаобращения: 13.05.2016)
2. Internet Live Stats. URL: http://www.internetlivestats.com/ (датаобращения: 15.04.2017)
3. Selmanovic D.. The 10 Most Common Mistakes Web Developers Make. URL: https://www.toptal.com/web/top-10-mistakes-that-web-developers-make (дата обращения: 15.04.2017)
4. HelmkeM., JosephE., ReyJ., BallewP., HillB.The Official Ubuntu Book. Upper Saddle River, NJ: Prentice Hall, 2014. 368 c.
5. Simpson K. You Don't Know JS: ES6 & Beyond. Sebastopol, CA: O'Reilly Media, 2015. 280 с.
6. Composer. URL: https://getcomposer.org/doc/ (дата обращения 19.04.2016)
7. Npm Documentation. URL: https://docs.npmjs.com/ (датаобращения 19.04.2017)
8. Potencier F. The Twig Book. Paris: SensioLabs, 2017. 156 с.
9. Romer M. PHP Persistence: Concepts, Techniques and Practical Solutions with Doctrine. New York City, NA: Apress, 2016. 107 с.
10. Chacon S., Straub B. Pro Git. New York City, NA: Apress, 2016. 456 с.
11. Chaudhary M., Kumar A. Birmingham. PhpStorm Cookbook. Birmingham: Packt Publishing, 2014. 256 с.
12. Webpack. URL: https://webpack.js.org/ (дата обращения 10.04.2017)
13. Material Design Light. URL: https://getmdl.io/ (датаобращения 21.04.2017)
14. Less.js: Getting started. URL:http://lesscss.org/ (датаобращения 21.04.2017)
15. Potencier F. Symfony. The Book. Paris: SensioLabs, 2016. 219 с.
16. Stones R. Beginning Databases with PostgreSQL: From Novice to Professional. New York City, NA: Apress, 2016. 664 с.
17. Hopkins C. The MVC Pattern and PHP. URL: https://www.sitepoint.com/the-mvc-pattern-and-php-1/ (дата обращения 11.04.2017)
18. BiererDoug. PHP 7 ProgrammingCookbook. Birmingham: Packt, 2016. 610 с.
19. A Framework or a CMS? What is better to choose? URL: http://www.web-and-development.com/a-framework-or-a-cms-what-is-better-to-choose/ (дата обращения 11.04.2017)
20. SymfonyversusFlatPHP. URL: https://symfony.com/doc/current/introduction/from_flat_php_to_symfony2.html (дата обращения 11.04.2017)
21. Symfony. URL: https://www.drupal.org/project/symfony (дата обращения 11.04.2017)
22. FOSUserBundle. URL: http://knpbundles.com/FriendsOfSymfony/FOSUserBundle (дата обращения 11.04.2017)
23. SonataAdminBundle. URL: https://sonata-project.org/bundles/admin/3-x/doc/index.html (дата обращения 11.04.2017)
24. MethodologyBEM. URL: https://en.bem.info/methodology/ (дата обращения 20.04.2017)
25. Robokassa user manual. URL: https://docs.robokassa.ru/en/ (датаобращения 25.04.2017)
26. CronHowto. URL: https://help.ubuntu.com/community/CronHowto (дата обращения 25.04.2017)
27. BergmannS. PHPUnitManual. Siegburg: Sebastian Bergmann, 2017. 175 с.
28. PHP Coding Standards Fixer. URL: http://cs.sensiolabs.org/ (датаобращения 10.06.2017)
Размещено на http://www.allbest.ru/
Приложение A. Конфигурационныефайлы
/app/config/parameters.yml
/.idea/
/var/
/vendor/
/web/assets/
/web/cache/
/web/upload/
/node_modules/
/bower_components/
.php_cs.cache
/web/bundles/
Листинг 19. Содержимоефайла.gitignore
{
"name": "symfony-game-shop",
"version": "0.0.1",
"dependencies": {
"assets-webpack-plugin": "^3.2.0",
"autoprefixer": "^6.3.6",
"babel-core": "^6.17.0",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.16.0",
"bower": "^1.7.2",
"clean-webpack-plugin": "^0.1.8",
"clndr": "^1.4.6",
"css-loader": "^0.23.1",
"css-mqpacker": "^4.0.1",
"exports-loader": "^0.6.2",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"getmdl-select": "^1.0.4",
"imports-loader": "^0.6.5",
"jquery": "^1.11.3",
"jquery-mousewheel": "^3.1.13",
"jquery-ui": "^1.10.5",
"jquery.dotdotdot": "^1.7.4",
"less": "^2.3.1",
"less-loader": "^2.2.2",
"material-design-lite": "^1.3.0",
"moment": "^2.15.1",
"normalize.css": "^4.1.1",
"nouislider": "^9.2.0",
"picturefill": "^3.0.2",
"postcss-loader": "^0.8.2",
"resolve-url-loader": "^1.4.3",
"slick-carousel": "^1.6.0",
"style-loader": "^0.13.0",
"underscore": "^1.8.3",
"url-loader": "^0.5.7",
"webpack": "^1.12.11"
}
}
Листинг20. Содержимоефайлаpackage.json
Приложение B. КласссущностиGame
<?php
declare(strict_types=1);
namespace Difuks\DazzleBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Game.
*
* @ORM\Table(name="game")
* @ORM\Entity(repositoryClass="Difuks\DazzleBundle\Repository\GameRepository")
*/
classGame
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* @var string
*
* @ORM\Column(name="code", type="string", length=255, unique=true)
*/
private $code;
/**
* @var Image
*
* @ORM\ManyToOne(targetEntity="Image", cascade={"persist"})
* @ORM\JoinColumn(nullable=true)
*/
private $logo;
/**
* @var \DateTime
*
* @ORM\Column(name="release_date", type="datetime")
*/
private $releaseDate;
/**
* @var string
*
* @ORM\Column(name="site", type="string", length=255)
*/
private $site;
/**
* @var string
*
* @ORM\Column(name="video", type="string", length=255)
*/
private $video;
/**
* @var int
*
* @ORM\Column(name="age_restrictions", type="integer")
*/
private $ageRestrictions;
/**
* @var string
*
* @ORM\Column(name="description", type="text")
*/
private $description;
/**
* @var string
*
* @ORM\Column(name="system_requirements", type="text")
*/
private $systemRequirements;
/**
* @var float
*
* @ORM\Column(name="price", type="float")
*/
private $price;
/**
* @var Genre[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Genre", inversedBy="games", cascade={"persist"})
* @ORM\JoinTable(name="game_genre")
*/
private $genres;
/**
* @var Developer
*
* @ORM\ManyToOne(targetEntity="Developer", cascade={"persist"}, inversedBy="games")
* @ORM\JoinColumn(nullable=false)
*/
private $developer;
/**
* @var Publisher
*
* @ORM\ManyToOne(targetEntity="Publisher", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $publisher;
/**
* @var Image[]|ArrayCollection
*
* @ORM\ManyToMany(targetEntity="Image", inversedBy="games", cascade={"persist"})
* @ORM\JoinTable(name="game_screenshots")
*/
private $screenshots;
/**
* @var Key[]|ArrayCollection
*
* @ORM\OneToMany(
* targetEntity="Key",
* mappedBy="game",
* orphanRemoval=true,
* cascade={"persist"}
* )
*/
private $keys;
/**
* @var bool
*
* @ORM\Column(name="multiplayer", type="boolean")
*/
private $multiplayer;
/**
* @var Review[]|ArrayCollection
*
* @ORM\OneToMany(
* targetEntity="Review",
* mappedBy="game",
* orphanRemoval=true,
* cascade={"persist"}
* )
*/
private $reviews;
/**
* @var Discount
*
* @ORM\ManyToOne(targetEntity="Discount", inversedBy="games", cascade={"persist"})
* @ORM\JoinColumn(nullable=true, onDelete="SET NULL")
*/
private $discount;
/**
* @var BasketProduct[]|ArrayCollection
*
* @ORM\OneToMany(
* targetEntity="BasketProduct",
* mappedBy="game",
* orphanRemoval=true
* )
*/
private $basketProducts;
/**
* @var int
*
* @ORM\Column(name="buy_count", type="integer", nullable=true)
*/
private $buyCount;
/**
* @var \DateTime
*
* @ORM\Column(name="last_buy", type="datetime", nullable=true)
*/
private $lastBuy;
/**
* @var float
*
* @ORM\Column(name="rate", type="float", nullable=true)
*/
private $rate;
/**
* @var bool
*
* @ORM\Column(name="is_released", type="boolean", options={"default" : true})
*/
private $isReleased;
/**
* @var bool
*
* @ORM\Column(name="is_rus", type="boolean", options={"default" : true})
*/
private $isRus;
publicfunction__construct()
{
$this->releaseDate = new \DateTime();
$this->genres = new ArrayCollection();
$this->keys = new ArrayCollection();
$this->screenshots = new ArrayCollection();
$this->reviews = new ArrayCollection();
$this->basketProducts = new ArrayCollection();
$this->buyCount = 0;
$this->rate = 0;
}
publicfunction__toString()
{
return (string) $this->getName();
}
publicfunctiongetId()
{
return $this->id;
}
publicfunctionsetName(string $name)
{
$this->name = $name;
return $this;
}
publicfunctiongetName()
{
return $this->name;
}
publicfunctionsetCode(string $code)
{
$this->code = $code;
return $this;
}
publicfunctiongetCode()
{
return $this->code;
}
publicfunctionsetLogo(Image $logo)
{
$this->logo = $logo;
return $this;
}
publicfunctiongetLogo()
{
return $this->logo;
}
publicfunctionsetReleaseDate(\DateTime $releaseDate)
{
$this->releaseDate = $releaseDate;
return $this;
}
publicfunctiongetReleaseDate()
{
return $this->releaseDate;
}
publicfunctionsetSite(string $site)
{
$this->site = $site;
return $this;
}
publicfunctiongetSite()
{
return $this->site;
}
publicfunctionsetVideo(string $video)
{
$this->video = $video;
return $this;
}
publicfunctiongetVideo()
{
return $this->video;
}
publicfunctionsetAgeRestrictions(int $ageRestrictions)
{
$this->ageRestrictions = $ageRestrictions;
return $this;
}
publicfunctiongetAgeRestrictions()
{
return $this->ageRestrictions;
}
publicfunctionsetDescription(string $description)
{
$this->description = $description;
return $this;
}
publicfunctiongetDescription()
{
return $this->description;
}
publicfunctionsetSystemRequirements(string $systemRequirements)
{
$this->systemRequirements = $systemRequirements;
return $this;
}
publicfunctiongetSystemRequirements()
{
return $this->systemRequirements;
}
publicfunctionsetPrice(float $price)
{
$this->price = $price;
return $this;
}
publicfunctiongetPrice()
{
return (int) $this->price;
}
publicfunctionaddGenre(Genre $genre)
{
$this->genres->add($genre);
return $this;
}
publicfunctionremoveGenre(Genre $genre)
{
$this->genres->removeElement($genre);
return $this;
}
publicfunctiongetGenres()
{
return $this->genres;
}
publicfunctionsetGenres(ArrayCollection $genres)
{
$this->genres = $genres;
}
publicfunctionaddScreenshot(Image $screenshot)
{
$this->screenshots->add($screenshot);
return $this;
}
publicfunctionremoveScreenshot(Image $screenshot)
{
$this->screenshots->removeElement($screenshot);
return $this;
}
publicfunctiongetScreenshots()
{
return $this->screenshots;
}
publicfunctionsetScreenshots(ArrayCollection $screenshots)
{
$this->screenshots = $screenshots;
}
publicfunctiongetDeveloper()
{
return $this->developer;
}
publicfunctionsetDeveloper(Developer $developer)
{
$this->developer = $developer;
return $this;
}
publicfunctiongetPublisher()
{
return $this->publisher;
}
publicfunctionsetPublisher(Publisher $publisher)
{
$this->publisher = $publisher;
return $this;
}
publicfunctiongetKeys()
{
$unPayedKeys = new ArrayCollection();
foreach ($this->keys as $key) {
if ($key->getStatus() == 0) {
$unPayedKeys->add($key);
}
}
return $unPayedKeys;
}
publicfunctionaddKey(Key $key)
{
$this->keys->add($key);
$key->setGame($this);
return $this;
}
publicfunctionremoveKey(Key $key)
{
$this->keys->removeElement($key);
return $this;
}
publicfunctiongetReviews()
{
return $this->reviews;
}
publicfunctionaddReview(Review $review)
{
$this->reviews->add($review);
$review->setGame($this);
$rate = $review->getRate();
$count = 1;
foreach ($this->getReviews() as $newReview) {
Подобные документы
Обзор существующих технологий разработки программного обеспечения. Описание платформы NET Framework. Принцип работы платформы: компиляция исходного кода; процесс загрузки и исполнения кода; IL-код и верификация. Новые возможности платформы NET Framework.
реферат [30,7 K], добавлен 01.03.2011Разработка программного приложения по учету договоров с поставщиками и клиентами для строительного предприятия. Особенности использования технологии Net Framework 2.0 в алгоритмически-логическом аспекте на основе реляционной базы, управляемой языком SQL.
курсовая работа [3,0 M], добавлен 25.06.2011Изучение сведений o плaтфopме .NET Framework. Характеристика метoдов дocтупa к бaзaм дaнныx. Рaзpaбoтка пpилoжения "Пocтaвкa и pеaлизaция пpoгpaммнoгo oбеcпечения", coдеpжaщего бaзу дaнныx и pacкpывaющего вcе acпекты paзpaбoтки бaзы дaнныx нa языке C+.
курсовая работа [1,8 M], добавлен 12.12.2011Розробка гри "Арканоід", з можливістю гри, як одного та і двох гравців одночасно на одному гральному полі, за допомогою Visual Studio 2008 з XNA Framework. Аналіз предметної галузі. Опис концептуальної моделі. Реалізація взаємодії між гравцем та системою.
курсовая работа [5,5 M], добавлен 21.01.2010Общие сведения о платформе Microsoft NET Framework. Разработка приложения "Поставка и реализация программного обеспечения", содержащего базу данных о каталогах адресов в Internet. Описание логической структуры. Требования к техническому обеспечению.
курсовая работа [2,4 M], добавлен 28.06.2011Выбор языка и среды программирования, технологий доступа и взаимодействия с источниками данных. Требования к разработке информационной системы. Проектирование базы данных информационной системы учета и взаимодействующего с ней приложения .NET Framework.
курсовая работа [1,3 M], добавлен 17.05.2013Разработка программного решения по созданию мобильного приложения. Изучение технологий для разработки приложений. Анализ работы торговых агентов. Обоснование выбора языка программирования. Проектирование интерфейса структуры и верстка, листинг программы.
дипломная работа [2,2 M], добавлен 08.06.2017Описание платформы NET Framework. База данных Microsoft Access. Разработка Windows приложения. Модель программирования Windows Forms. Функциональное назначение программы. Входные и выходные данные. Требования к техническому и программному обеспечению.
курсовая работа [2,2 M], добавлен 15.03.2015Характеристика и состав Microsoft Solution Framework. Модель команды, её характеристики. Цели качества команды проекта. Модель процессов, её содержание. Принципы управления рисками. Утверждение целей и границ, плана проекта. Модель приложений MSF.
презентация [752,5 K], добавлен 10.05.2013История развития средств создания и демонстрации компьютерных презентаций. Краткий обзор программных средств: MS Power Point, Open Office Impress, iWork и некоторых online – сервисов. Проектирование и разработка презентации на основе собственного шаблона.
курсовая работа [7,5 M], добавлен 19.12.2012