mirror of
https://github.com/doctrine/doctrine-website.git
synced 2026-03-23 22:32:11 +01:00
Add events functionality to the website.
This commit is contained in:
15
.travis.yml
15
.travis.yml
@@ -12,8 +12,15 @@ cache:
|
||||
php:
|
||||
- 7.2
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
||||
before_install:
|
||||
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{,.disabled} || echo "xdebug not available"
|
||||
- mysql -e 'CREATE DATABASE doctrine_website_test;'
|
||||
- sudo mysql -e "use mysql; update user set authentication_string=PASSWORD('VdtLtifRh4gt37T') where User='root'; update user set plugin='mysql_native_password'; FLUSH PRIVILEGES;"
|
||||
- sudo mysql_upgrade -u root -pVdtLtifRh4gt37T
|
||||
- sudo service mysql restart
|
||||
|
||||
install:
|
||||
- rm composer.lock
|
||||
@@ -37,11 +44,7 @@ jobs:
|
||||
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,}
|
||||
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
|
||||
script:
|
||||
- ./bin/console sync-repositories --env=test
|
||||
- ./bin/console build-website-data --env=test
|
||||
- ./bin/console build-docs --env=test
|
||||
- ./bin/console build-website --env=test
|
||||
- ./vendor/bin/phpunit --coverage-clover clover.xml
|
||||
- ./phpunit --build-all --coverage-clover clover.xml
|
||||
after_script:
|
||||
- wget https://scrutinizer-ci.com/ocular.phar
|
||||
- php ocular.phar code-coverage:upload --format=php-clover clover.xml
|
||||
@@ -54,4 +57,4 @@ jobs:
|
||||
- stage: Code Quality
|
||||
env: STATIC_ANALYSIS
|
||||
install: travis_retry composer install --prefer-dist
|
||||
script: vendor/bin/phpstan analyse
|
||||
script: ./vendor/bin/phpstan analyse
|
||||
|
||||
@@ -15,13 +15,18 @@
|
||||
"algolia/algoliasearch-client-php": "^1.27",
|
||||
"cache/doctrine-adapter": "^1.0",
|
||||
"doctrine/inflector": "^1.3",
|
||||
"doctrine/migrations": "^2.0",
|
||||
"doctrine/orm": "^2.6",
|
||||
"doctrine/rst-parser": "^0.1",
|
||||
"doctrine/skeleton-mapper": "^1.0",
|
||||
"doctrine/static-website-generator": "^1.0",
|
||||
"erusev/parsedown": "^1.7",
|
||||
"knplabs/github-api": "^2.10",
|
||||
"pelago/emogrifier": "^2.1",
|
||||
"php-http/guzzle6-adapter": "^1.1",
|
||||
"scrivo/highlight.php": "^9.14",
|
||||
"sendgrid/sendgrid": "^7.3",
|
||||
"stripe/stripe-php": "^6.34",
|
||||
"symfony/config": "^4.2",
|
||||
"symfony/console": "^4.2",
|
||||
"symfony/dependency-injection": "^4.2",
|
||||
@@ -38,8 +43,9 @@
|
||||
"phpstan/phpstan-phpunit": "^0.10",
|
||||
"phpstan/phpstan-strict-rules": "^0.10",
|
||||
"phpunit/phpunit": "^7.0",
|
||||
"symfony/css-selector": "^4.0",
|
||||
"symfony/dom-crawler": "^4.0",
|
||||
"symfony/css-selector": "^4.0"
|
||||
"symfony/var-dumper": "^4.2"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
|
||||
1051
composer.lock
generated
1051
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,9 @@
|
||||
parameters:
|
||||
doctrine.website.algolia.app_id: 'YVYTFT9XMW'
|
||||
doctrine.website.algolia.admin_api_key: '1234'
|
||||
doctrine.website.stripe.publishable_key: 'pk_test_V7rmF8ac3GbakeSJYvp4u0a8003RPO66vC'
|
||||
doctrine.website.stripe.secret_key: ''
|
||||
doctrine.website.send_grid.api_key: ''
|
||||
|
||||
doctrine.website.webpack_build_dir: '%doctrine.website.root_dir%/.webpack-build'
|
||||
doctrine.website.projects_dir: '%doctrine.website.root_dir%/projects'
|
||||
@@ -10,7 +13,8 @@ parameters:
|
||||
|
||||
doctrine.website.title: Doctrine
|
||||
doctrine.website.subtitle: PHP Database Tools
|
||||
doctrine.website.url: http://lcl.doctrine-project.org
|
||||
doctrine.website.url: https://lcl.doctrine-project.org
|
||||
doctrine.website.assets_url: https://www.doctrine-project.org
|
||||
doctrine.website.keywords: [php, mysql, orm, dbal, database, mongodb, odm, annotations, migrations, cache, couchdb]
|
||||
doctrine.website.description: >
|
||||
The Doctrine Project is the home to several PHP libraries primarily
|
||||
|
||||
@@ -4,3 +4,4 @@ imports:
|
||||
parameters:
|
||||
doctrine.website.url: 'https://www.doctrine-project.org'
|
||||
doctrine.website.google_analytics_tracking_id: 'UA-288343-7'
|
||||
doctrine.website.stripe.publishable_key: 'pk_live_54QFCgqHDYHZ1tFxg95JhYRR00kICoxvNS'
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
imports:
|
||||
- { resource: config.yml }
|
||||
|
||||
parameters:
|
||||
doctrine.website.mysql.password: 'VdtLtifRh4gt37T'
|
||||
|
||||
services:
|
||||
Doctrine\Website\Github\GithubProjectContributors:
|
||||
alias: Doctrine\Website\Github\TestGithubProjectContributors
|
||||
|
||||
@@ -23,6 +23,32 @@ parameters:
|
||||
defaults:
|
||||
title: RST Example
|
||||
|
||||
events:
|
||||
path: /events.html
|
||||
controller: Doctrine\Website\Controllers\EventsController::index
|
||||
defaults:
|
||||
menuSlug: events
|
||||
|
||||
event_suggest:
|
||||
path: /events/suggest.html
|
||||
controller: Doctrine\Website\Controllers\EventsController::suggest
|
||||
defaults:
|
||||
menuSlug: events
|
||||
|
||||
event:
|
||||
path: /events/{id}/{slug}.html
|
||||
controller: Doctrine\Website\Controllers\EventsController::view
|
||||
provider: Doctrine\Website\Requests\EventRequests::getEvents
|
||||
defaults:
|
||||
menuSlug: events
|
||||
|
||||
event_cfp:
|
||||
path: /events/{id}/{slug}/cfp.html
|
||||
controller: Doctrine\Website\Controllers\EventsController::cfp
|
||||
provider: Doctrine\Website\Requests\EventRequests::getEvents
|
||||
defaults:
|
||||
menuSlug: events
|
||||
|
||||
styleguide:
|
||||
path: /styleguide.html
|
||||
defaults:
|
||||
@@ -46,6 +72,8 @@ parameters:
|
||||
path: /partners/{slug}.html
|
||||
controller: Doctrine\Website\Controllers\PartnersController::view
|
||||
provider: Doctrine\Website\Requests\PartnerRequests::getPartners
|
||||
defaults:
|
||||
menuSlug: partners
|
||||
|
||||
consulting:
|
||||
path: /consulting.html
|
||||
|
||||
@@ -3,6 +3,11 @@
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
|
||||
<parameters>
|
||||
<parameter key="doctrine.website.mysql.user">root</parameter>
|
||||
<parameter key="doctrine.website.mysql.password"></parameter>
|
||||
</parameters>
|
||||
|
||||
<services>
|
||||
<defaults autowire="true" autoconfigure="true" public="false">
|
||||
<bind key="$rootDir">%doctrine.website.root_dir%</bind>
|
||||
@@ -13,13 +18,10 @@
|
||||
<bind key="$sourceDir">%doctrine.website.source_dir%</bind>
|
||||
<bind key="$projectsData">%doctrine.website.projects_data%</bind>
|
||||
<bind key="$webpackBuildDir">%doctrine.website.webpack_build_dir%</bind>
|
||||
<bind key="$teamMembers">%doctrine.website.team_members%</bind>
|
||||
<bind key="$templatesDir">%doctrine.website.templates_dir%</bind>
|
||||
<bind key="$doctrineUsers">%doctrine.website.doctrine_users%</bind>
|
||||
<bind key="$sponsors">%doctrine.website.sponsors%</bind>
|
||||
<bind key="$partners">%doctrine.website.partners%</bind>
|
||||
<bind key="$projectIntegrationTypes">%doctrine.website.project_integration.types%</bind>
|
||||
<bind key="$routes">%doctrine.website.routes%</bind>
|
||||
<bind key="$stripePublishableKey">%doctrine.website.stripe.publishable_key%</bind>
|
||||
</defaults>
|
||||
|
||||
<prototype namespace="Doctrine\Website\" resource="../lib/*" />
|
||||
@@ -55,6 +57,20 @@
|
||||
</argument>
|
||||
</service>
|
||||
|
||||
<service id="Pelago\Emogrifier">
|
||||
<call method="disableStyleBlocksParsing" />
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\Email\RenderEmail" autowire="false">
|
||||
<argument type="service" id="Pelago\Emogrifier" />
|
||||
<argument>%doctrine.website.templates_dir%</argument>
|
||||
<argument type="collection">
|
||||
<argument type="service" id="Doctrine\Website\Twig\MainExtension" />
|
||||
<argument type="service" id="Doctrine\Website\Twig\ProjectExtension" />
|
||||
<argument type="service" id="Doctrine\StaticWebsiteGenerator\Twig\RoutingExtension" />
|
||||
</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\StaticWebsiteGenerator\Twig\TwigRenderer" alias="Doctrine\StaticWebsiteGenerator\Twig\StringTwigRenderer" />
|
||||
|
||||
<service id="Doctrine\Website\Github\GithubProjectContributors" alias="Doctrine\Website\Github\ProdGithubProjectContributors" />
|
||||
@@ -121,6 +137,9 @@
|
||||
<service id="Doctrine\Common\Cache\FilesystemCache" autowire="false">
|
||||
<argument>%doctrine.website.cache_dir%/fscache</argument>
|
||||
</service>
|
||||
<service id="SendGrid" class="SendGrid" autowire="true">
|
||||
<argument>%doctrine.website.send_grid.api_key%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\StaticWebsiteGenerator\Controller\ControllerProvider">
|
||||
<argument type="collection">
|
||||
@@ -128,6 +147,7 @@
|
||||
<argument type="service" id="Doctrine\Website\Controllers\BlogController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\ConsultingController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\DocumentationController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\EventsController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\HomepageController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\PartnersController" />
|
||||
<argument type="service" id="Doctrine\Website\Controllers\ProjectController" />
|
||||
@@ -140,6 +160,7 @@
|
||||
<service id="Doctrine\StaticWebsiteGenerator\Request\RequestCollectionProvider">
|
||||
<argument type="collection">
|
||||
<argument type="service" id="Doctrine\Website\Requests\ContributorRequests" />
|
||||
<argument type="service" id="Doctrine\Website\Requests\EventRequests" />
|
||||
<argument type="service" id="Doctrine\Website\Requests\PartnerRequests" />
|
||||
<argument type="service" id="Doctrine\Website\Requests\ProjectRequests" />
|
||||
<argument type="service" id="Doctrine\Website\Requests\ProjectVersionRequests" />
|
||||
@@ -151,7 +172,7 @@
|
||||
<argument>%doctrine.website.algolia.admin_api_key%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\StaticWebsiteGenerator\Site">
|
||||
<service id="Doctrine\Website\Site">
|
||||
<argument>%doctrine.website.title%</argument>
|
||||
<argument>%doctrine.website.subtitle%</argument>
|
||||
<argument>%doctrine.website.url%</argument>
|
||||
@@ -159,8 +180,11 @@
|
||||
<argument>%doctrine.website.description%</argument>
|
||||
<argument>%doctrine.website.env%</argument>
|
||||
<argument>%doctrine.website.google_analytics_tracking_id%</argument>
|
||||
<argument>%doctrine.website.assets_url%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\StaticWebsiteGenerator\Site" alias="Doctrine\Website\Site" />
|
||||
|
||||
<service id="Doctrine\RST\Kernel">
|
||||
<argument type="service" id="Doctrine\RST\Configuration" />
|
||||
|
||||
@@ -208,7 +232,7 @@
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\BlogPostHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -216,7 +240,7 @@
|
||||
<argument>Doctrine\Website\Model\BlogPost</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\Repositories\ContributorRepository" autowire="false">
|
||||
<service id="Doctrine\Website\Repositories\ContributorRepository" autowire="false" public="true">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
@@ -227,7 +251,7 @@
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\ContributorHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -240,13 +264,17 @@
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service" id="Doctrine\Website\DataSources\DoctrineUsers" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\DataSources\ArrayDataSource">
|
||||
<argument>%doctrine.website.doctrine_users%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>Doctrine\Website\Model\DoctrineUser</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\DoctrineUserHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -259,13 +287,17 @@
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service" id="Doctrine\Website\DataSources\Sponsors" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\DataSources\ArrayDataSource">
|
||||
<argument>%doctrine.website.sponsors%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>Doctrine\Website\Model\Sponsor</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\SponsorHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -278,13 +310,17 @@
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service" id="Doctrine\Website\DataSources\Partners" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\DataSources\ArrayDataSource">
|
||||
<argument>%doctrine.website.partners%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>Doctrine\Website\Model\Partner</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\PartnerHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -303,7 +339,7 @@
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\ProjectHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -322,7 +358,7 @@
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\ProjectContributorHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -341,7 +377,7 @@
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\SitemapPageHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -354,13 +390,17 @@
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service" id="Doctrine\Website\DataSources\TeamMembers" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\DataSources\ArrayDataSource">
|
||||
<argument>%doctrine.website.team_members%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>Doctrine\Website\Model\TeamMember</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\Hydrator\BasicObjectHydrator">
|
||||
<service class="Doctrine\Website\Hydrators\TeamMemberHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
</service>
|
||||
</argument>
|
||||
@@ -368,6 +408,31 @@
|
||||
<argument>Doctrine\Website\Model\TeamMember</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\Repositories\EventRepository" autowire="false" public="true">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\SkeletonMapper\DataSource\DataSourceObjectDataRepository" autowire="false">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\DataSources\ArrayDataSource">
|
||||
<argument>%doctrine.website.events%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument>Doctrine\Website\Model\Event</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectFactory" />
|
||||
<argument type="service">
|
||||
<service class="Doctrine\Website\Hydrators\EventHydrator">
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\ObjectManager" />
|
||||
<argument type="service" id="Doctrine\Website\Model\Entity\EventParticipantRepository" />
|
||||
<argument>%doctrine.website.env%</argument>
|
||||
</service>
|
||||
</argument>
|
||||
<argument type="service" id="Doctrine\Common\EventManager" />
|
||||
<argument>Doctrine\Website\Model\Event</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\SkeletonMapper\ObjectRepository\ObjectRepositoryFactory" autowire="false">
|
||||
<call method="addObjectRepository">
|
||||
<argument>Doctrine\Website\Model\BlogPost</argument>
|
||||
@@ -409,6 +474,11 @@
|
||||
<argument type="service" id="Doctrine\Website\Repositories\TeamMemberRepository" />
|
||||
</call>
|
||||
|
||||
<call method="addObjectRepository">
|
||||
<argument>Doctrine\Website\Model\Event</argument>
|
||||
<argument type="service" id="Doctrine\Website\Repositories\EventRepository" />
|
||||
</call>
|
||||
|
||||
<call method="addObjectRepository">
|
||||
<argument>Doctrine\Website\Model\SitemapPage</argument>
|
||||
<argument type="service" id="Doctrine\Website\Repositories\SitemapPageRepository" />
|
||||
@@ -422,5 +492,50 @@
|
||||
<argument type="service" id="Doctrine\SkeletonMapper\Mapping\ClassMetadataFactory" />
|
||||
<argument type="service" id="Doctrine\Common\EventManager" />
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\ORM\Configuration">
|
||||
<factory class="Doctrine\ORM\Tools\Setup" method="createAnnotationMetadataConfiguration" />
|
||||
<argument type="collection">
|
||||
<argument>%doctrine.website.root_dir%/lib/Model/Entity</argument>
|
||||
</argument>
|
||||
<argument>%doctrine.website.debug%</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\ORM\EntityManager">
|
||||
<factory class="Doctrine\ORM\EntityManager" method="create" />
|
||||
<argument type="service" id="Doctrine\DBAL\Connection" />
|
||||
<argument type="service" id="Doctrine\ORM\Configuration" />
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Website\Model\Entity\EventParticipantRepository">
|
||||
<factory service="Doctrine\ORM\EntityManager" method="getRepository" />
|
||||
<argument>Doctrine\Website\Model\Entity\EventParticipant</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\DBAL\Connection">
|
||||
<factory class="Doctrine\DBAL\DriverManager" method="getConnection" />
|
||||
<argument type="collection">
|
||||
<argument key="dbname">doctrine_website_%doctrine.website.env%</argument>
|
||||
<argument key="user">%doctrine.website.mysql.user%</argument>
|
||||
<argument key="password">%doctrine.website.mysql.password%</argument>
|
||||
<argument key="host">localhost</argument>
|
||||
<argument key="driver">pdo_mysql</argument>
|
||||
</argument>
|
||||
</service>
|
||||
|
||||
<service id="Doctrine\Migrations\Configuration\Configuration">
|
||||
<call method="setName">
|
||||
<argument>Doctrine Website Migrations</argument>
|
||||
</call>
|
||||
<call method="setMigrationsNamespace">
|
||||
<argument>Doctrine\Website\Migrations</argument>
|
||||
</call>
|
||||
<call method="setAllOrNothing">
|
||||
<argument>true</argument>
|
||||
</call>
|
||||
<call method="setMigrationsDirectory">
|
||||
<argument>%doctrine.website.root_dir%/lib/Migrations</argument>
|
||||
</call>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
||||
99
data/events.yml
Normal file
99
data/events.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
parameters:
|
||||
# New events go at the top and get an incremented ID.
|
||||
doctrine.website.events:
|
||||
-
|
||||
id: 3
|
||||
sku:
|
||||
test: 'sku_F4LUc9SGRiCBUK'
|
||||
prod: 'sku_F4M3RdEwiscrtD'
|
||||
name: 'Getting started with Doctrine MongoDB ODM'
|
||||
slug: 'getting-started-with-doctrine-mongodb-odm'
|
||||
price: 5.00
|
||||
joinUrl: 'https://zoom.us/webinar/register/9215578873469/WN_fwSHnCzCQ7WO_8Tao5rr7Q'
|
||||
startDate: '2019-07-16'
|
||||
endDate: '2019-07-16'
|
||||
registrationStartDate: '2019-05-01'
|
||||
registrationEndDate: '2019-07-16'
|
||||
sponsors: []
|
||||
speakers:
|
||||
-
|
||||
name: 'alcaeus'
|
||||
topic: 'Getting started with Doctrine MongoDB ODM'
|
||||
topicSlug: 'getting-started-with-doctrine-mongodb-odm'
|
||||
description: >
|
||||
You've used Doctrine ORM but never used MongoDB? With MongoDB ODM you can use familiar
|
||||
tools with a different kind of database. This webinar will focus on getting MongoDB
|
||||
set up and designing our first documents for MongoDB. We'll cover differences in schema
|
||||
design between relational databases and MongoDB and also use more advanced features like
|
||||
aggregation pipelines and document validation.
|
||||
|
||||
schedule:
|
||||
-
|
||||
topicSlug: 'getting-started-with-doctrine-mongodb-odm'
|
||||
startDate: '2019-07-16 11:00'
|
||||
endDate: '2019-07-16 12:00'
|
||||
|
||||
-
|
||||
id: 2
|
||||
sku:
|
||||
test: 'sku_F4IaFRrVzZ4m4G'
|
||||
prod: 'sku_F4M21kt1HC36by'
|
||||
name: 'Doctrine for Beginners'
|
||||
slug: 'doctrine-for-beginners'
|
||||
price: 5.00
|
||||
joinUrl: 'https://zoom.us/webinar/register/1315578887109/WN_4yo28dTASHyTqibhpuvo-Q'
|
||||
startDate: '2019-05-28'
|
||||
endDate: '2019-05-28'
|
||||
registrationStartDate: '2019-05-01'
|
||||
registrationEndDate: '2019-05-27'
|
||||
sponsors: []
|
||||
speakers:
|
||||
-
|
||||
name: 'jwage'
|
||||
topic: 'Doctrine for Beginners'
|
||||
topicSlug: 'doctrine-for-beginners'
|
||||
description: >
|
||||
Come to this talk prepared to learn about the Doctrine PHP open source project.
|
||||
The Doctrine project has been around for over a decade and has evolved from database
|
||||
abstraction software that dates back to the PEAR days. The packages provided by the
|
||||
Doctrine project have been downloaded almost a billion times from packagist. In
|
||||
this talk we will take you through how to get started with Doctrine and how to take
|
||||
advantage of some of the more advanced features.
|
||||
|
||||
schedule:
|
||||
-
|
||||
topicSlug: 'doctrine-for-beginners'
|
||||
startDate: '2019-05-28 11:00'
|
||||
endDate: '2019-05-28 12:00'
|
||||
|
||||
-
|
||||
id: 1
|
||||
sku:
|
||||
test: 'sku_F4LV13ZF4c5aUn'
|
||||
prod: 'sku_F4M2PSGAcfOGyO'
|
||||
name: 'PHP Internals for the Inquisitive Developer'
|
||||
slug: 'php-internals-for-the-inquisitive-developer'
|
||||
price: 5.00
|
||||
joinUrl: 'https://zoom.us/webinar/register/8515577702351/WN_OBdv-AOHRWyNeIC2FXZ-IQ'
|
||||
startDate: '2019-09-10'
|
||||
endDate: '2019-09-10'
|
||||
registrationStartDate: '2019-05-01'
|
||||
registrationEndDate: '2019-09-10'
|
||||
sponsors: []
|
||||
speakers:
|
||||
-
|
||||
name: 'jmikola'
|
||||
topic: 'PHP Internals for the Inquisitive Developer'
|
||||
topicSlug: 'php-internals-for-the-inquisitive-developer'
|
||||
description: >
|
||||
Even if you have no intention of becoming a PHP core developer or creating a PECL
|
||||
extension, cursory knowledge of PHP's inner workings can prove useful. This session
|
||||
will examine the lifecycle of a PHP request and equip you with essential knowledge
|
||||
and tools that can be used to diagnose the occasional segfault or language bug,
|
||||
decipher what a poorly documented SPL class actually does, and confidently answer why
|
||||
a PHP or C implementation is most warranted for a given problem.
|
||||
schedule:
|
||||
-
|
||||
topicSlug: 'php-internals-for-the-inquisitive-developer'
|
||||
startDate: '2019-09-10 11:00'
|
||||
endDate: '2019-09-10 12:00'
|
||||
@@ -4,19 +4,34 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Tools\Console\Command as DBALCommand;
|
||||
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
|
||||
use Doctrine\Migrations\Configuration\Configuration as MigrationsConfiguration;
|
||||
use Doctrine\Migrations\Tools\Console\Command as MigrationsCommand;
|
||||
use Doctrine\Migrations\Tools\Console\Helper\ConfigurationHelper;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\ORM\Tools\Console\Command as ORMCommand;
|
||||
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
|
||||
use Doctrine\Website\Commands\BuildAllCommand;
|
||||
use Doctrine\Website\Commands\BuildDocsCommand;
|
||||
use Doctrine\Website\Commands\BuildWebsiteCommand;
|
||||
use Doctrine\Website\Commands\BuildWebsiteDataCommand;
|
||||
use Doctrine\Website\Commands\ClearBuildCacheCommand;
|
||||
use Doctrine\Website\Commands\DeployCommand;
|
||||
use Doctrine\Website\Commands\EventParticipantsCommand;
|
||||
use Doctrine\Website\Commands\SyncRepositoriesCommand;
|
||||
use Stripe;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Console\Application as BaseApplication;
|
||||
use Symfony\Component\Console\Helper\HelperSet;
|
||||
use Symfony\Component\Console\Helper\QuestionHelper;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
|
||||
use function date_default_timezone_set;
|
||||
use function file_exists;
|
||||
use function getenv;
|
||||
use function realpath;
|
||||
@@ -27,40 +42,72 @@ class Application
|
||||
/** @var BaseApplication */
|
||||
private $application;
|
||||
|
||||
/** @var BuildDocsCommand */
|
||||
private $buildDocsCommand;
|
||||
|
||||
/** @var BuildWebsiteCommand */
|
||||
private $buildWebsiteCommand;
|
||||
|
||||
/** @var BuildWebsiteDataCommand */
|
||||
private $buildWebsiteDataCommand;
|
||||
|
||||
/** @var ClearBuildCacheCommand */
|
||||
private $clearBuildCacheCommand;
|
||||
|
||||
/** @var DeployCommand */
|
||||
private $deployCommand;
|
||||
|
||||
/** @var SyncRepositoriesCommand */
|
||||
private $syncRepositoriesCommand;
|
||||
|
||||
public function __construct(
|
||||
BaseApplication $application,
|
||||
EntityManager $em,
|
||||
Connection $connection,
|
||||
MigrationsConfiguration $migrationsConfiguration,
|
||||
BuildAllCommand $buildAllCommand,
|
||||
BuildDocsCommand $buildDocsCommand,
|
||||
BuildWebsiteCommand $buildWebsiteCommand,
|
||||
BuildWebsiteDataCommand $buildWebsiteDataCommand,
|
||||
ClearBuildCacheCommand $clearBuildCacheCommand,
|
||||
DeployCommand $deployCommand,
|
||||
SyncRepositoriesCommand $syncRepositoriesCommand
|
||||
SyncRepositoriesCommand $syncRepositoriesCommand,
|
||||
EventParticipantsCommand $eventParticipantsCommand
|
||||
) {
|
||||
$this->application = $application;
|
||||
$this->buildDocsCommand = $buildDocsCommand;
|
||||
$this->buildWebsiteCommand = $buildWebsiteCommand;
|
||||
$this->buildWebsiteDataCommand = $buildWebsiteDataCommand;
|
||||
$this->clearBuildCacheCommand = $clearBuildCacheCommand;
|
||||
$this->deployCommand = $deployCommand;
|
||||
$this->syncRepositoriesCommand = $syncRepositoriesCommand;
|
||||
$this->application = $application;
|
||||
|
||||
$this->application->add($buildAllCommand);
|
||||
$this->application->add($buildDocsCommand);
|
||||
$this->application->add($buildWebsiteCommand);
|
||||
$this->application->add($buildWebsiteDataCommand);
|
||||
$this->application->add($clearBuildCacheCommand);
|
||||
$this->application->add($deployCommand);
|
||||
$this->application->add($syncRepositoriesCommand);
|
||||
$this->application->add($eventParticipantsCommand);
|
||||
|
||||
$this->application->setHelperSet(new HelperSet([
|
||||
'question' => new QuestionHelper(),
|
||||
'db' => new ConnectionHelper($connection),
|
||||
'em' => new EntityManagerHelper($em),
|
||||
'configuration' => new ConfigurationHelper($connection, $migrationsConfiguration),
|
||||
]));
|
||||
|
||||
$this->application->addCommands([
|
||||
// DBAL Commands
|
||||
new DBALCommand\ReservedWordsCommand(),
|
||||
new DBALCommand\RunSqlCommand(),
|
||||
|
||||
// ORM Commands
|
||||
new ORMCommand\ClearCache\CollectionRegionCommand(),
|
||||
new ORMCommand\ClearCache\EntityRegionCommand(),
|
||||
new ORMCommand\ClearCache\MetadataCommand(),
|
||||
new ORMCommand\ClearCache\QueryCommand(),
|
||||
new ORMCommand\ClearCache\QueryRegionCommand(),
|
||||
new ORMCommand\ClearCache\ResultCommand(),
|
||||
new ORMCommand\SchemaTool\CreateCommand(),
|
||||
new ORMCommand\SchemaTool\UpdateCommand(),
|
||||
new ORMCommand\SchemaTool\DropCommand(),
|
||||
new ORMCommand\EnsureProductionSettingsCommand(),
|
||||
new ORMCommand\GenerateProxiesCommand(),
|
||||
new ORMCommand\RunDqlCommand(),
|
||||
new ORMCommand\ValidateSchemaCommand(),
|
||||
new ORMCommand\InfoCommand(),
|
||||
new ORMCommand\MappingDescribeCommand(),
|
||||
|
||||
// Migrations Commands
|
||||
new MigrationsCommand\DumpSchemaCommand(),
|
||||
new MigrationsCommand\ExecuteCommand(),
|
||||
new MigrationsCommand\GenerateCommand(),
|
||||
new MigrationsCommand\LatestCommand(),
|
||||
new MigrationsCommand\MigrateCommand(),
|
||||
new MigrationsCommand\RollupCommand(),
|
||||
new MigrationsCommand\StatusCommand(),
|
||||
new MigrationsCommand\VersionCommand(),
|
||||
new MigrationsCommand\UpToDateCommand(),
|
||||
new MigrationsCommand\DiffCommand(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function run(InputInterface $input) : int
|
||||
@@ -74,43 +121,49 @@ class Application
|
||||
);
|
||||
$this->application->getDefinition()->addOption($inputOption);
|
||||
|
||||
$this->application->add($this->buildDocsCommand);
|
||||
$this->application->add($this->buildWebsiteCommand);
|
||||
$this->application->add($this->buildWebsiteDataCommand);
|
||||
$this->application->add($this->clearBuildCacheCommand);
|
||||
$this->application->add($this->deployCommand);
|
||||
$this->application->add($this->syncRepositoriesCommand);
|
||||
|
||||
return $this->application->run($input);
|
||||
}
|
||||
|
||||
public function getConsoleApplication() : BaseApplication
|
||||
{
|
||||
return $this->application;
|
||||
}
|
||||
|
||||
public static function getContainer(string $env) : ContainerBuilder
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->setParameter('doctrine.website.env', $env);
|
||||
$container->setParameter('doctrine.website.debug', $env !== 'prod');
|
||||
$container->setParameter('doctrine.website.root_dir', realpath(__DIR__ . '/..'));
|
||||
$container->setParameter('doctrine.website.config_dir', realpath(__DIR__ . '/../config'));
|
||||
$container->setParameter('doctrine.website.cache_dir', realpath(__DIR__ . '/../cache'));
|
||||
$container->setParameter('doctrine.website.github.http_token', getenv('doctrine_website_github_http_token'));
|
||||
|
||||
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$loader->load('services.xml');
|
||||
$xmlConfigLoader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$xmlConfigLoader->load('services.xml');
|
||||
|
||||
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$loader->load('partners.yml');
|
||||
$loader->load('projects.yml');
|
||||
$loader->load('routes.yml');
|
||||
$loader->load('sponsors.yml');
|
||||
$loader->load('team_members.yml');
|
||||
$yamlConfigLoader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
|
||||
$yamlConfigLoader->load('routes.yml');
|
||||
|
||||
$loader->load(sprintf('config_%s.yml', $env));
|
||||
$yamlConfigLoader->load(sprintf('config_%s.yml', $env));
|
||||
|
||||
if (file_exists($container->getParameter('doctrine.website.config_dir') . '/local.yml')) {
|
||||
$loader->load('local.yml');
|
||||
$yamlConfigLoader->load('local.yml');
|
||||
}
|
||||
|
||||
$dataLoader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../data'));
|
||||
$dataLoader->load('events.yml');
|
||||
$dataLoader->load('partners.yml');
|
||||
$dataLoader->load('projects.yml');
|
||||
$dataLoader->load('sponsors.yml');
|
||||
$dataLoader->load('team_members.yml');
|
||||
|
||||
$container->compile();
|
||||
|
||||
Stripe\Stripe::setApiKey($container->getParameter('doctrine.website.stripe.secret_key'));
|
||||
|
||||
date_default_timezone_set('America/New_York');
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
||||
|
||||
109
lib/Commands/BuildAllCommand.php
Normal file
109
lib/Commands/BuildAllCommand.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Commands;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use function array_merge;
|
||||
use function array_unshift;
|
||||
use function assert;
|
||||
use function is_array;
|
||||
use function is_bool;
|
||||
use function is_string;
|
||||
use function sprintf;
|
||||
|
||||
class BuildAllCommand extends Command
|
||||
{
|
||||
/** @var string */
|
||||
private $rootDir;
|
||||
|
||||
/** @var string */
|
||||
private $env;
|
||||
|
||||
public function __construct(
|
||||
string $rootDir,
|
||||
string $env
|
||||
) {
|
||||
$this->rootDir = $rootDir;
|
||||
$this->env = $env;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->setName('build-all')
|
||||
->setDescription('Build all website components.')
|
||||
->addArgument(
|
||||
'build-dir',
|
||||
InputArgument::OPTIONAL,
|
||||
'The directory where the build repository is cloned.',
|
||||
sprintf('%s/build-%s', $this->rootDir, $this->env)
|
||||
)
|
||||
->addOption(
|
||||
'publish',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Publish the build to GitHub Pages.'
|
||||
)
|
||||
->addOption(
|
||||
'clear-build-cache',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Clear the build cache before building everything.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : int
|
||||
{
|
||||
$commands = [
|
||||
'sync-repositories' => [],
|
||||
'build-website-data' => [],
|
||||
'build-docs' => [],
|
||||
'build-website' => [
|
||||
'build-dir' => $input->getArgument('build-dir'),
|
||||
'--publish' => $input->getOption('publish'),
|
||||
],
|
||||
];
|
||||
|
||||
$clearBuildCache = $input->getOption('clear-build-cache');
|
||||
assert(is_bool($clearBuildCache));
|
||||
|
||||
if ($clearBuildCache) {
|
||||
array_unshift($commands, 'clear-build-cache');
|
||||
}
|
||||
|
||||
foreach ($commands as $command => $arguments) {
|
||||
assert(is_string($command));
|
||||
assert(is_array($arguments));
|
||||
|
||||
$output->writeln(sprintf('Executing <info>./doctrine %s</info>', $command));
|
||||
|
||||
if ($this->runCommand($command, $arguments) === 1) {
|
||||
$output->writeln(sprintf('Failed running command "%s".', $command));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $arguments
|
||||
*/
|
||||
private function runCommand(string $command, array $arguments) : int
|
||||
{
|
||||
$input = new ArrayInput(array_merge(['command' => $command], $arguments));
|
||||
|
||||
return $this->getApplication()->find($command)
|
||||
->run($input, new ConsoleOutput());
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,11 @@ use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Symfony\Component\Process\Process;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function date;
|
||||
use function in_array;
|
||||
use function ini_set;
|
||||
use function is_bool;
|
||||
@@ -20,9 +24,18 @@ use function is_string;
|
||||
use function mkdir;
|
||||
use function realpath;
|
||||
use function sprintf;
|
||||
use function time;
|
||||
|
||||
class BuildWebsiteCommand extends Command
|
||||
{
|
||||
private const WATCH_DIRS = [
|
||||
'config',
|
||||
'data',
|
||||
'lib',
|
||||
'source',
|
||||
'templates',
|
||||
];
|
||||
|
||||
/** @var WebsiteBuilder */
|
||||
private $websiteBuilder;
|
||||
|
||||
@@ -60,6 +73,12 @@ class BuildWebsiteCommand extends Command
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Publish the build to GitHub Pages.'
|
||||
)
|
||||
->addOption(
|
||||
'watch',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Watch for changes and build the website when changes are detected.'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -87,8 +106,60 @@ class BuildWebsiteCommand extends Command
|
||||
throw new InvalidArgumentException(sprintf('Could not find build directory'));
|
||||
}
|
||||
|
||||
$this->websiteBuilder->build($output, $buildDir, $this->env, $publish);
|
||||
$watch = $input->getOption('watch');
|
||||
assert(is_bool($watch));
|
||||
|
||||
if ($watch) {
|
||||
$this->watch($output);
|
||||
} else {
|
||||
$this->websiteBuilder->build($output, $buildDir, $this->env, $publish);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function watch(OutputInterface $output) : void
|
||||
{
|
||||
$lastWebsiteBuild = time();
|
||||
|
||||
while (true) {
|
||||
$finder = $this->createWatchFinder($lastWebsiteBuild);
|
||||
|
||||
if (! $finder->hasResults()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$output->writeln('Found changes');
|
||||
|
||||
$this->buildWebsiteSubProcess($output);
|
||||
|
||||
$lastWebsiteBuild = time();
|
||||
}
|
||||
}
|
||||
|
||||
private function createWatchFinder(int $lastWebsiteBuild) : Finder
|
||||
{
|
||||
return (new Finder())
|
||||
->in($this->getWatchDirs())
|
||||
->date(sprintf('>= %s', date('Y-m-d H:i:s', $lastWebsiteBuild)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function getWatchDirs() : array
|
||||
{
|
||||
return array_map(function (string $dir) : string {
|
||||
return $this->rootDir . '/' . $dir;
|
||||
}, self::WATCH_DIRS);
|
||||
}
|
||||
|
||||
private function buildWebsiteSubProcess(OutputInterface $output) : void
|
||||
{
|
||||
(new Process(['bin/console', 'build-website'], $this->rootDir))
|
||||
->setTty(true)
|
||||
->mustRun(static function ($type, $buffer) use ($output) : void {
|
||||
$output->write($buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
183
lib/Commands/EventParticipantsCommand.php
Normal file
183
lib/Commands/EventParticipantsCommand.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Commands;
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Doctrine\Website\Event\EmailParticipants;
|
||||
use Doctrine\Website\Event\GetStripeEventParticipants;
|
||||
use Doctrine\Website\Model\Entity\EventParticipant;
|
||||
use Doctrine\Website\Model\Entity\EventParticipantRepository;
|
||||
use Doctrine\Website\Model\Event;
|
||||
use Doctrine\Website\Repositories\EventRepository;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
use function array_filter;
|
||||
use function array_map;
|
||||
use function assert;
|
||||
use function count;
|
||||
use function in_array;
|
||||
use function is_bool;
|
||||
use function sprintf;
|
||||
|
||||
class EventParticipantsCommand extends Command
|
||||
{
|
||||
/** @var EventRepository */
|
||||
private $eventRepository;
|
||||
|
||||
/** @var EventParticipantRepository */
|
||||
private $eventParticipantRepository;
|
||||
|
||||
/** @var GetStripeEventParticipants */
|
||||
private $getStripeEventParticipants;
|
||||
|
||||
/** @var EmailParticipants */
|
||||
private $emailParticipants;
|
||||
|
||||
/** @var EntityManager */
|
||||
private $entityManager;
|
||||
|
||||
public function __construct(
|
||||
EventRepository $eventRepository,
|
||||
EventParticipantRepository $eventParticipantRepository,
|
||||
GetStripeEventParticipants $getStripeEventParticipants,
|
||||
EmailParticipants $emailParticipants,
|
||||
EntityManager $entityManager
|
||||
) {
|
||||
$this->eventRepository = $eventRepository;
|
||||
$this->eventParticipantRepository = $eventParticipantRepository;
|
||||
$this->getStripeEventParticipants = $getStripeEventParticipants;
|
||||
$this->emailParticipants = $emailParticipants;
|
||||
$this->entityManager = $entityManager;
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure() : void
|
||||
{
|
||||
$this
|
||||
->setName('event-participants')
|
||||
->setDescription('Command to check for event participants using the Stripe API.')
|
||||
->addOption(
|
||||
'save',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'Save new participants that are found.'
|
||||
)
|
||||
->addOption(
|
||||
'email',
|
||||
null,
|
||||
InputOption::VALUE_NONE,
|
||||
'E-Mail new participants that are found.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output) : int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
|
||||
$events = $this->eventRepository->findUpcomingEvents();
|
||||
|
||||
foreach ($events as $event) {
|
||||
$io->title(sprintf('%s Participants', $event->getName()));
|
||||
|
||||
$eventParticipants = $this->getStripeEventParticipants->__invoke($event);
|
||||
|
||||
if ($eventParticipants === []) {
|
||||
$io->warning(sprintf('No participants found for "%s". Get out there and market!', $event->getName()));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$newEventParticipants = $this->getNewEventParticipants($eventParticipants);
|
||||
|
||||
$save = $input->getOption('save');
|
||||
assert(is_bool($save));
|
||||
|
||||
if ($save) {
|
||||
$this->saveEventParticipants($newEventParticipants);
|
||||
}
|
||||
|
||||
$email = $input->getOption('email');
|
||||
assert(is_bool($email));
|
||||
|
||||
if ($email) {
|
||||
$this->emailEventParticipants($io, $event, $newEventParticipants);
|
||||
}
|
||||
|
||||
$header = ['E-Mail', 'Quantity', 'New'];
|
||||
|
||||
$rows = $this->createEventParticipantsTableRows(
|
||||
$eventParticipants,
|
||||
$newEventParticipants
|
||||
);
|
||||
|
||||
$io->table($header, $rows);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param EventParticipant[] $eventParticipants
|
||||
* @param EventParticipant[] $newEventParticipants
|
||||
*
|
||||
* @return mixed[][]
|
||||
*/
|
||||
private function createEventParticipantsTableRows(
|
||||
array $eventParticipants,
|
||||
array $newEventParticipants
|
||||
) : array {
|
||||
return array_map(
|
||||
static function (EventParticipant $participant) use ($newEventParticipants) : array {
|
||||
$isNew = in_array($participant, $newEventParticipants, true) ? 'Yes' : 'No';
|
||||
|
||||
return [$participant->getEmail(), $participant->getQuantity(), $isNew];
|
||||
},
|
||||
$eventParticipants
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventParticipant[] $eventParticipants
|
||||
*
|
||||
* @return EventParticipant[]
|
||||
*/
|
||||
private function getNewEventParticipants(array $eventParticipants) : array
|
||||
{
|
||||
return array_filter($eventParticipants, function (EventParticipant $eventParticipant) {
|
||||
return $this->eventParticipantRepository
|
||||
->findOneByEmail($eventParticipant->getEmail()) === null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventParticipant[] $eventParticipants
|
||||
*/
|
||||
private function saveEventParticipants(array $eventParticipants) : void
|
||||
{
|
||||
foreach ($eventParticipants as $eventParticipant) {
|
||||
$this->entityManager->persist($eventParticipant);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventParticipant[] $eventParticipants
|
||||
*/
|
||||
private function emailEventParticipants(
|
||||
SymfonyStyle $io,
|
||||
Event $event,
|
||||
array $eventParticipants
|
||||
) : void {
|
||||
$this->emailParticipants->__invoke($event, $eventParticipants);
|
||||
|
||||
$io->text(sprintf('E-mailed <info>%d</info> participants.', count($eventParticipants)));
|
||||
}
|
||||
}
|
||||
49
lib/Controllers/EventsController.php
Normal file
49
lib/Controllers/EventsController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Controllers;
|
||||
|
||||
use Doctrine\StaticWebsiteGenerator\Controller\Response;
|
||||
use Doctrine\Website\Repositories\EventRepository;
|
||||
|
||||
final class EventsController
|
||||
{
|
||||
/** @var EventRepository */
|
||||
private $eventRepository;
|
||||
|
||||
public function __construct(EventRepository $eventRepository)
|
||||
{
|
||||
$this->eventRepository = $eventRepository;
|
||||
}
|
||||
|
||||
public function index() : Response
|
||||
{
|
||||
$upcomingEvents = $this->eventRepository->findUpcomingEvents();
|
||||
$pastEvents = $this->eventRepository->findPastEvents();
|
||||
|
||||
return new Response([
|
||||
'upcomingEvents' => $upcomingEvents,
|
||||
'pastEvents' => $pastEvents,
|
||||
]);
|
||||
}
|
||||
|
||||
public function view(string $id, string $slug) : Response
|
||||
{
|
||||
$event = $this->eventRepository->findOneById((int) $id);
|
||||
|
||||
return new Response(['event' => $event], '/event.html.twig');
|
||||
}
|
||||
|
||||
public function cfp(string $id, string $slug) : Response
|
||||
{
|
||||
$event = $this->eventRepository->findOneById((int) $id);
|
||||
|
||||
return new Response(['event' => $event], '/event-cfp.html.twig');
|
||||
}
|
||||
|
||||
public function suggest() : Response
|
||||
{
|
||||
return new Response([]);
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,17 @@ namespace Doctrine\Website\DataSources;
|
||||
|
||||
use Doctrine\SkeletonMapper\DataSource\DataSource;
|
||||
|
||||
class TeamMembers implements DataSource
|
||||
final class ArrayDataSource implements DataSource
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private $teamMembers;
|
||||
private $sourceRows;
|
||||
|
||||
/**
|
||||
* @param mixed[] $teamMembers
|
||||
* @param mixed[] $sourceRows
|
||||
*/
|
||||
public function __construct(array $teamMembers)
|
||||
public function __construct(array $sourceRows)
|
||||
{
|
||||
$this->teamMembers = $teamMembers;
|
||||
$this->sourceRows = $sourceRows;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,6 +24,6 @@ class TeamMembers implements DataSource
|
||||
*/
|
||||
public function getSourceRows() : array
|
||||
{
|
||||
return $this->teamMembers;
|
||||
return $this->sourceRows;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DataSources;
|
||||
|
||||
use Doctrine\SkeletonMapper\DataSource\DataSource;
|
||||
|
||||
class DoctrineUsers implements DataSource
|
||||
{
|
||||
/** @var mixed[][] */
|
||||
private $doctrineUsers;
|
||||
|
||||
/**
|
||||
* @param mixed[][] $doctrineUsers
|
||||
*/
|
||||
public function __construct(array $doctrineUsers)
|
||||
{
|
||||
$this->doctrineUsers = $doctrineUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
*/
|
||||
public function getSourceRows() : array
|
||||
{
|
||||
return $this->doctrineUsers;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DataSources;
|
||||
|
||||
use Doctrine\SkeletonMapper\DataSource\DataSource;
|
||||
|
||||
class Partners implements DataSource
|
||||
{
|
||||
/** @var mixed[][] */
|
||||
private $partners;
|
||||
|
||||
/**
|
||||
* @param mixed[][] $partners
|
||||
*/
|
||||
public function __construct(array $partners)
|
||||
{
|
||||
$this->partners = $partners;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
*/
|
||||
public function getSourceRows() : array
|
||||
{
|
||||
return $this->partners;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\DataSources;
|
||||
|
||||
use Doctrine\SkeletonMapper\DataSource\DataSource;
|
||||
|
||||
class Sponsors implements DataSource
|
||||
{
|
||||
/** @var mixed[][] */
|
||||
private $sponsors;
|
||||
|
||||
/**
|
||||
* @param mixed[][] $sponsors
|
||||
*/
|
||||
public function __construct(array $sponsors)
|
||||
{
|
||||
$this->sponsors = $sponsors;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
*/
|
||||
public function getSourceRows() : array
|
||||
{
|
||||
return $this->sponsors;
|
||||
}
|
||||
}
|
||||
@@ -72,9 +72,10 @@ class Deployer
|
||||
$output->write($buffer);
|
||||
});
|
||||
|
||||
// build the docs, website and publish
|
||||
// execute migrations, build the website and publish it.
|
||||
$deployCommand = sprintf(
|
||||
'cd /data/doctrine-website-%s && ./bin/console sync-repositories && ./bin/console build-website-data && ./bin/console build-docs && ./bin/console build-website /data/doctrine-website-build-%s --env=%s --publish',
|
||||
'cd /data/doctrine-website-%s && ./bin/console migrations:migrate --no-interaction --env=%s && ./bin/console build-all /data/doctrine-website-build-%s --env=%s --publish',
|
||||
$this->env,
|
||||
$this->env,
|
||||
$this->env,
|
||||
$this->env
|
||||
|
||||
80
lib/Email/RenderEmail.php
Normal file
80
lib/Email/RenderEmail.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Email;
|
||||
|
||||
use Pelago\Emogrifier;
|
||||
use Twig\Environment;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Twig\Loader\LoaderInterface;
|
||||
use function strip_tags;
|
||||
use function trim;
|
||||
|
||||
final class RenderEmail
|
||||
{
|
||||
/** @var Emogrifier */
|
||||
private $emogrifier;
|
||||
|
||||
/** @var string */
|
||||
private $templatesDir;
|
||||
|
||||
/** @var AbstractExtension[] */
|
||||
private $extensions;
|
||||
|
||||
/**
|
||||
* @param AbstractExtension[] $extensions
|
||||
*/
|
||||
public function __construct(
|
||||
Emogrifier $emogrifier,
|
||||
string $templatesDir,
|
||||
array $extensions
|
||||
) {
|
||||
$this->emogrifier = $emogrifier;
|
||||
$this->templatesDir = $templatesDir;
|
||||
$this->extensions = $extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
public function __invoke(string $template, array $parameters) : RenderedEmail
|
||||
{
|
||||
$twig = $this->createTwigEnvironment($this->createFilesystemLoader());
|
||||
|
||||
$template = $twig->loadTemplate($template);
|
||||
|
||||
$subject = $template->renderBlock('subject', $parameters);
|
||||
$inlineCss = $template->renderBlock('inline_css', $parameters);
|
||||
$bodyText = $template->renderBlock('full_body_text', $parameters);
|
||||
$bodyHtml = $template->renderBlock('full_body_html', $parameters);
|
||||
|
||||
if (trim($bodyText) === '') {
|
||||
$bodyText = strip_tags($template->renderBlock('body_html', $parameters));
|
||||
}
|
||||
|
||||
$this->emogrifier->setHtml($bodyHtml);
|
||||
$this->emogrifier->setCss($inlineCss);
|
||||
|
||||
$mergedHtml = $this->emogrifier->emogrify();
|
||||
|
||||
return new RenderedEmail($subject, $bodyText, $mergedHtml);
|
||||
}
|
||||
|
||||
private function createTwigEnvironment(LoaderInterface $loader) : Environment
|
||||
{
|
||||
$twig = new Environment($loader, ['strict_variables' => true]);
|
||||
|
||||
foreach ($this->extensions as $extension) {
|
||||
$twig->addExtension($extension);
|
||||
}
|
||||
|
||||
return $twig;
|
||||
}
|
||||
|
||||
private function createFilesystemLoader() : FilesystemLoader
|
||||
{
|
||||
return new FilesystemLoader($this->templatesDir);
|
||||
}
|
||||
}
|
||||
39
lib/Email/RenderedEmail.php
Normal file
39
lib/Email/RenderedEmail.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Email;
|
||||
|
||||
final class RenderedEmail
|
||||
{
|
||||
/** @var string */
|
||||
private $subject;
|
||||
|
||||
/** @var string */
|
||||
private $bodyText;
|
||||
|
||||
/** @var string */
|
||||
private $bodyHtml;
|
||||
|
||||
public function __construct(string $subject, string $bodyText, string $bodyHtml)
|
||||
{
|
||||
$this->subject = $subject;
|
||||
$this->bodyText = $bodyText;
|
||||
$this->bodyHtml = $bodyHtml;
|
||||
}
|
||||
|
||||
public function getSubject() : string
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
public function getBodyText() : string
|
||||
{
|
||||
return $this->bodyText;
|
||||
}
|
||||
|
||||
public function getBodyHtml() : string
|
||||
{
|
||||
return $this->bodyHtml;
|
||||
}
|
||||
}
|
||||
49
lib/Email/SendEmail.php
Normal file
49
lib/Email/SendEmail.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Email;
|
||||
|
||||
use Doctrine\Website\Site;
|
||||
use SendGrid;
|
||||
|
||||
final class SendEmail
|
||||
{
|
||||
/** @var Site */
|
||||
private $site;
|
||||
|
||||
/** @var SendGrid */
|
||||
private $sendGrid;
|
||||
|
||||
/** @var RenderEmail */
|
||||
private $renderEmail;
|
||||
|
||||
public function __construct(
|
||||
Site $site,
|
||||
SendGrid $sendGrid,
|
||||
RenderEmail $renderEmail
|
||||
) {
|
||||
$this->site = $site;
|
||||
$this->sendGrid = $sendGrid;
|
||||
$this->renderEmail = $renderEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $parameters
|
||||
*/
|
||||
public function __invoke(string $to, string $template, array $parameters = []) : void
|
||||
{
|
||||
$parameters['site'] = $this->site;
|
||||
|
||||
$renderedEmail = $this->renderEmail->__invoke($template, $parameters);
|
||||
|
||||
$email = new SendGrid\Mail\Mail();
|
||||
$email->setFrom('doctrine@doctrine-project.org', 'Doctrine');
|
||||
$email->setSubject($renderedEmail->getSubject());
|
||||
$email->addTo($to);
|
||||
$email->addContent('text/plain', $renderedEmail->getBodyText());
|
||||
$email->addContent('text/html', $renderedEmail->getBodyHtml());
|
||||
|
||||
$this->sendGrid->send($email);
|
||||
}
|
||||
}
|
||||
37
lib/Event/EmailParticipants.php
Normal file
37
lib/Event/EmailParticipants.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Event;
|
||||
|
||||
use Doctrine\Website\Email\SendEmail;
|
||||
use Doctrine\Website\Model\Entity\EventParticipant;
|
||||
use Doctrine\Website\Model\Event;
|
||||
|
||||
final class EmailParticipants
|
||||
{
|
||||
/** @var SendEmail */
|
||||
private $sendEmail;
|
||||
|
||||
public function __construct(SendEmail $sendEmail)
|
||||
{
|
||||
$this->sendEmail = $sendEmail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param EventParticipant[] $participants
|
||||
*/
|
||||
public function __invoke(Event $event, array $participants) : void
|
||||
{
|
||||
foreach ($participants as $participant) {
|
||||
$this->sendEmail->__invoke(
|
||||
$participant->getEmail(),
|
||||
'emails/events/participant-ticket.html.twig',
|
||||
[
|
||||
'event' => $event,
|
||||
'participant' => $participant,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
109
lib/Event/GetStripeEventParticipants.php
Normal file
109
lib/Event/GetStripeEventParticipants.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Event;
|
||||
|
||||
use Doctrine\Website\Model\Entity\EventParticipant;
|
||||
use Doctrine\Website\Model\Event;
|
||||
use Stripe;
|
||||
use function array_map;
|
||||
use function array_merge;
|
||||
use function array_values;
|
||||
use function end;
|
||||
use function iterator_to_array;
|
||||
use function strtotime;
|
||||
|
||||
final class GetStripeEventParticipants
|
||||
{
|
||||
/**
|
||||
* @return EventParticipant[]
|
||||
*/
|
||||
public function __invoke(Event $event) : array
|
||||
{
|
||||
$stripeCheckouts = $this->getAllEventStripeCheckouts($event);
|
||||
|
||||
$participants = [];
|
||||
|
||||
$customers = [];
|
||||
|
||||
foreach ($stripeCheckouts as $stripeCheckout) {
|
||||
$item = $stripeCheckout['data']['object']['display_items'][0];
|
||||
$sku = $item['sku']['id'];
|
||||
$quantity = $item['quantity'];
|
||||
$customerId = $stripeCheckout['data']['object']['customer'];
|
||||
|
||||
if ($sku !== $event->getSku()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! isset($customers[$customerId])) {
|
||||
$customers[$customerId] = Stripe\Customer::retrieve($customerId);
|
||||
}
|
||||
|
||||
$customer = $customers[$customerId];
|
||||
|
||||
if (! isset($participants[$customer['email']])) {
|
||||
$participants[$customer['email']] = [
|
||||
'email' => $customer['email'],
|
||||
'quantity' => $quantity,
|
||||
];
|
||||
} else {
|
||||
$participants[$customer['email']]['quantity'] += $quantity;
|
||||
}
|
||||
}
|
||||
|
||||
return array_map(static function (array $participant) use ($event) : EventParticipant {
|
||||
return new EventParticipant(
|
||||
$event,
|
||||
$participant['email'],
|
||||
$participant['quantity']
|
||||
);
|
||||
}, array_values($participants));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed[][]
|
||||
*/
|
||||
private function getAllEventStripeCheckouts(Event $event) : array
|
||||
{
|
||||
$allEventStripeCheckouts = [];
|
||||
$startingAfter = null;
|
||||
|
||||
while (true) {
|
||||
$eventStripeCheckouts = $this->getEventStripeCheckouts($event, $startingAfter);
|
||||
|
||||
$eventStripeCheckoutsArray = iterator_to_array($eventStripeCheckouts);
|
||||
|
||||
$allEventStripeCheckouts = array_merge(
|
||||
$allEventStripeCheckouts,
|
||||
$eventStripeCheckoutsArray
|
||||
);
|
||||
|
||||
if ($eventStripeCheckouts['has_more'] === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
$startingAfter = end($eventStripeCheckoutsArray)['id'];
|
||||
}
|
||||
|
||||
return $allEventStripeCheckouts;
|
||||
}
|
||||
|
||||
private function getEventStripeCheckouts(
|
||||
Event $event,
|
||||
?string $startingAfter = null
|
||||
) : Stripe\Collection {
|
||||
$parameters = [
|
||||
'created' => ['gt' => strtotime('1 year ago')],
|
||||
'limit' => 100,
|
||||
'type' => 'checkout.session.completed',
|
||||
];
|
||||
|
||||
if ($startingAfter !== null) {
|
||||
$parameters['starting_after'] = $startingAfter;
|
||||
}
|
||||
|
||||
return Stripe\Event::all($parameters);
|
||||
}
|
||||
}
|
||||
39
lib/Hydrators/BlogPostHydrator.php
Normal file
39
lib/Hydrators/BlogPostHydrator.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Website\Model\BlogPost;
|
||||
|
||||
/**
|
||||
* @property string $url
|
||||
* @property string $slug
|
||||
* @property string $title
|
||||
* @property string $authorName
|
||||
* @property string $authorEmail
|
||||
* @property string $contents
|
||||
* @property DateTimeImmutable $date
|
||||
*/
|
||||
final class BlogPostHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return BlogPost::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->url = (string) $data['url'] ?? '';
|
||||
$this->slug = (string) $data['slug'] ?? '';
|
||||
$this->title = (string) $data['title'] ?? '';
|
||||
$this->authorName = (string) $data['authorName'] ?? '';
|
||||
$this->authorEmail = (string) $data['authorEmail'] ?? '';
|
||||
$this->contents = (string) $data['contents'] ?? '';
|
||||
$this->date = $data['date'] ?? new DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
38
lib/Hydrators/ContributorHydrator.php
Normal file
38
lib/Hydrators/ContributorHydrator.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\Contributor;
|
||||
|
||||
/**
|
||||
* @property TeamMember|null $teamMember
|
||||
* @property string $github
|
||||
* @property string $avatarUrl
|
||||
* @property int $numCommits
|
||||
* @property int $numAdditions
|
||||
* @property int $numDeletions
|
||||
* @property Project[] $projects
|
||||
*/
|
||||
final class ContributorHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return Contributor::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->teamMember = $data['teamMember'] ?? null;
|
||||
$this->github = (string) ($data['github'] ?? '');
|
||||
$this->avatarUrl = (string) ($data['avatarUrl'] ?? '');
|
||||
$this->numCommits = (int) ($data['numCommits'] ?? 0);
|
||||
$this->numAdditions = (int) ($data['numAdditions'] ?? 0);
|
||||
$this->numDeletions = (int) ($data['numDeletions'] ?? 0);
|
||||
$this->projects = $data['projects'] ?? [];
|
||||
}
|
||||
}
|
||||
28
lib/Hydrators/DoctrineUserHydrator.php
Normal file
28
lib/Hydrators/DoctrineUserHydrator.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\DoctrineUser;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $url
|
||||
*/
|
||||
final class DoctrineUserHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return DoctrineUser::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->name = (string) $data['name'];
|
||||
$this->url = (string) $data['url'];
|
||||
}
|
||||
}
|
||||
169
lib/Hydrators/EventHydrator.php
Normal file
169
lib/Hydrators/EventHydrator.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use Doctrine\Website\Model\Address;
|
||||
use Doctrine\Website\Model\DateTimeRange;
|
||||
use Doctrine\Website\Model\Entity\EventParticipantRepository;
|
||||
use Doctrine\Website\Model\Event;
|
||||
use Doctrine\Website\Model\EventCfp;
|
||||
use Doctrine\Website\Model\EventLocation;
|
||||
use Doctrine\Website\Model\EventParticipants;
|
||||
use Doctrine\Website\Model\EventSchedule;
|
||||
use Doctrine\Website\Model\EventSpeakers;
|
||||
use Doctrine\Website\Model\EventSponsors;
|
||||
use Doctrine\Website\Model\EventType;
|
||||
use InvalidArgumentException;
|
||||
use function current;
|
||||
use function end;
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string $type
|
||||
* @property EventLocation|null $location
|
||||
* @property string $sku
|
||||
* @property string $joinUrl
|
||||
* @property EventCfp $cfp
|
||||
* @property EventSponsors $sponsors
|
||||
* @property EventSpeakers $speakers
|
||||
* @property EventSchedule $schedule
|
||||
* @property EventParticipants $participants
|
||||
* @property DateTimeRange $dateTimeRange
|
||||
* @property DateTimeRange $registrationDateTimeRange
|
||||
* @property string $description
|
||||
* @property float $price
|
||||
*/
|
||||
final class EventHydrator extends ModelHydrator
|
||||
{
|
||||
private const ENV_SKU_MAP = [
|
||||
'dev' => 'test',
|
||||
'prod' => 'prod',
|
||||
'staging' => 'test',
|
||||
'test' => 'test',
|
||||
];
|
||||
|
||||
/** @var EventParticipantRepository */
|
||||
private $eventParticipantRepository;
|
||||
|
||||
/** @var string */
|
||||
private $env;
|
||||
|
||||
public function __construct(
|
||||
ObjectManagerInterface $objectManager,
|
||||
EventParticipantRepository $eventParticipantRepository,
|
||||
string $env
|
||||
) {
|
||||
parent::__construct($objectManager);
|
||||
|
||||
$this->eventParticipantRepository = $eventParticipantRepository;
|
||||
$this->env = $env;
|
||||
}
|
||||
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return Event::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->id = (int) ($data['id'] ?? 0);
|
||||
$this->type = (string) ($data['type'] ?? EventType::WEBINAR);
|
||||
|
||||
if ($this->type === EventType::CONFERENCE) {
|
||||
if (! isset($data['location'])) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Event type of "%s" must provide a "location" field.', $this->type)
|
||||
);
|
||||
}
|
||||
|
||||
$this->location = new EventLocation(
|
||||
(string) ($data['location']['name'] ?? ''),
|
||||
new Address(
|
||||
(string) ($data['location']['address']['line1'] ?? ''),
|
||||
(string) ($data['location']['address']['line2'] ?? ''),
|
||||
(string) ($data['location']['address']['city'] ?? ''),
|
||||
(string) ($data['location']['address']['state'] ?? ''),
|
||||
(string) ($data['location']['address']['zipCode'] ?? ''),
|
||||
(string) ($data['location']['address']['countryCode'] ?? '')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($data['sku'])) {
|
||||
if (! isset(self::ENV_SKU_MAP[$this->env])) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid env "%s".', $this->env));
|
||||
}
|
||||
|
||||
$skuKey = self::ENV_SKU_MAP[$this->env];
|
||||
|
||||
if (! isset($data['sku'][$skuKey])) {
|
||||
throw new InvalidArgumentException(
|
||||
sprintf('Sku key with "%s" does not exist.', $skuKey)
|
||||
);
|
||||
}
|
||||
|
||||
$this->sku = (string) ($data['sku'][$skuKey] ?? '');
|
||||
} else {
|
||||
$this->sku = '';
|
||||
}
|
||||
|
||||
$this->name = (string) ($data['name'] ?? '');
|
||||
$this->slug = (string) ($data['slug'] ?? '');
|
||||
$this->joinUrl = (string) ($data['joinUrl'] ?? '');
|
||||
|
||||
$this->cfp = new EventCfp(
|
||||
(string) ($data['cfp']['googleFormId'] ?? ''),
|
||||
new DateTimeRange(
|
||||
new DateTimeImmutable($data['cfp']['startDate'] ?? ''),
|
||||
new DateTimeImmutable($data['cfp']['endDate'] ?? '')
|
||||
)
|
||||
);
|
||||
|
||||
$this->sponsors = new EventSponsors($data);
|
||||
$this->speakers = new EventSpeakers($data, $this->objectManager);
|
||||
$this->schedule = new EventSchedule($data, $this->speakers);
|
||||
|
||||
if ($data['schedule'] !== []) {
|
||||
$firstSlot = current($data['schedule']);
|
||||
$lastSlot = end($data['schedule']);
|
||||
|
||||
$this->dateTimeRange = new DateTimeRange(
|
||||
new DateTimeImmutable($firstSlot['startDate'] ?? ''),
|
||||
new DateTimeImmutable($lastSlot['endDate'] ?? '')
|
||||
);
|
||||
} else {
|
||||
$this->dateTimeRange = new DateTimeRange(
|
||||
new DateTimeImmutable($data['startDate'] ?? ''),
|
||||
new DateTimeImmutable($data['endDate'] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
$this->registrationDateTimeRange = new DateTimeRange(
|
||||
isset($data['registrationStartDate'])
|
||||
? new DateTimeImmutable($data['registrationStartDate'])
|
||||
: $this->dateTimeRange->getStart(),
|
||||
isset($data['registrationEndDate'])
|
||||
? new DateTimeImmutable($data['registrationEndDate'])
|
||||
: $this->dateTimeRange->getEnd()
|
||||
);
|
||||
|
||||
$this->description = (string) ($data['description'] ?? '');
|
||||
|
||||
$this->price = (float) ($data['price'] ?? 0.00);
|
||||
|
||||
$this->participants = new EventParticipants(
|
||||
$data['id'],
|
||||
$this->eventParticipantRepository
|
||||
);
|
||||
}
|
||||
}
|
||||
81
lib/Hydrators/ModelHydrator.php
Normal file
81
lib/Hydrators/ModelHydrator.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\ObjectHydrator;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use ReflectionProperty;
|
||||
|
||||
abstract class ModelHydrator extends ObjectHydrator
|
||||
{
|
||||
/** @var ObjectManagerInterface */
|
||||
protected $objectManager;
|
||||
|
||||
/** @var object */
|
||||
private $object;
|
||||
|
||||
/** @var ClassMetadataInterface */
|
||||
private $classMetadata;
|
||||
|
||||
/** @var ReflectionProperty[] */
|
||||
private $reflectionProperties;
|
||||
|
||||
public function __construct(ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->objectManager = $objectManager;
|
||||
$this->classMetadata = $this->objectManager->getClassMetadata($this->getClassName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
abstract protected function doHydrate(array $data) : void;
|
||||
|
||||
abstract protected function getClassName() : string;
|
||||
|
||||
/**
|
||||
* @param object $object
|
||||
* @param mixed[] $data
|
||||
*
|
||||
* @phpcsSuppress SlevomatCodingStandard.TypeHints.TypeHintDeclaration.MissingParameterTypeHint
|
||||
*/
|
||||
public function hydrate($object, array $data) : void
|
||||
{
|
||||
$this->object = $object;
|
||||
|
||||
$this->doHydrate($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get(string $field)
|
||||
{
|
||||
return $this->getReflectionProperty($field)->getValue($this->object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set(string $field, $value) : void
|
||||
{
|
||||
$this->getReflectionProperty($field)->setValue($this->object, $value);
|
||||
}
|
||||
|
||||
private function getReflectionProperty(string $field) : ReflectionProperty
|
||||
{
|
||||
$key = $this->getClassName() . '::' . $field;
|
||||
|
||||
if (! isset($this->reflectionProperties[$key])) {
|
||||
$reflectionProperty = $this->classMetadata->getReflectionClass()->getProperty($field);
|
||||
$reflectionProperty->setAccessible(true);
|
||||
|
||||
$this->reflectionProperties[$key] = $reflectionProperty;
|
||||
}
|
||||
|
||||
return $this->reflectionProperties[$key];
|
||||
}
|
||||
}
|
||||
57
lib/Hydrators/PartnerHydrator.php
Normal file
57
lib/Hydrators/PartnerHydrator.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\Partner;
|
||||
use Doctrine\Website\Model\PartnerDetails;
|
||||
use Doctrine\Website\Model\UtmParameters;
|
||||
use function array_merge;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $slug
|
||||
* @property string $url
|
||||
* @property string $logo
|
||||
* @property string $bio
|
||||
* @property bool $featured
|
||||
* @property PartnerDetails $details
|
||||
* @property UtmParameters $utmParameters
|
||||
*/
|
||||
final class PartnerHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return Partner::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->name = (string) ($data['name'] ?? '');
|
||||
$this->slug = (string) ($data['slug'] ?? '');
|
||||
$this->url = (string) ($data['url'] ?? '');
|
||||
$this->logo = (string) ($data['logo'] ?? '');
|
||||
$this->bio = (string) ($data['bio'] ?? '');
|
||||
$this->featured = (bool) ($data['featured'] ?? false);
|
||||
|
||||
$this->details = new PartnerDetails(
|
||||
(string) ($data['details']['label'] ?? ''),
|
||||
$data['details']['items'] ?? []
|
||||
);
|
||||
|
||||
$this->utmParameters = new UtmParameters(
|
||||
array_merge(
|
||||
[
|
||||
'utm_source' => 'doctrine',
|
||||
'utm_medium' => 'website',
|
||||
'utm_campaign' => 'partners',
|
||||
],
|
||||
$data['utmParameters'] ?? []
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
41
lib/Hydrators/ProjectContributorHydrator.php
Normal file
41
lib/Hydrators/ProjectContributorHydrator.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\ProjectContributor;
|
||||
|
||||
/**
|
||||
* @property TeamMember|null $teamMember
|
||||
* @property string $projectSlug
|
||||
* @property Project $project
|
||||
* @property string $github
|
||||
* @property string $avatarUrl
|
||||
* @property int $numCommits
|
||||
* @property int $numAdditions
|
||||
* @property int $numDeletions
|
||||
*/
|
||||
final class ProjectContributorHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return ProjectContributor::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->teamMember = $data['teamMember'] ?? null;
|
||||
$this->projectSlug = (string) ($data['projectSlug'] ?? '');
|
||||
$this->project = $data['project'] ?? new Project();
|
||||
$this->github = (string) ($data['github'] ?? '');
|
||||
$this->avatarUrl = (string) ($data['avatarUrl'] ?? '');
|
||||
$this->numCommits = (int) ($data['numCommits'] ?? 0);
|
||||
$this->numAdditions = (int) ($data['numAdditions'] ?? 0);
|
||||
$this->numDeletions = (int) ($data['numDeletions'] ?? 0);
|
||||
}
|
||||
}
|
||||
90
lib/Hydrators/ProjectHydrator.php
Normal file
90
lib/Hydrators/ProjectHydrator.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\ProjectIntegrationType;
|
||||
use Doctrine\Website\Model\ProjectStats;
|
||||
use Doctrine\Website\Model\ProjectVersion;
|
||||
|
||||
/**
|
||||
* @property bool $active
|
||||
* @property bool $archived
|
||||
* @property string $name
|
||||
* @property string $shortName
|
||||
* @property string $slug
|
||||
* @property string $docsSlug
|
||||
* @property string $composerPackageName
|
||||
* @property string $repositoryName
|
||||
* @property bool $isIntegration
|
||||
* @property string $integrationFor
|
||||
* @property string $docsRepositoryName
|
||||
* @property string $docsPath
|
||||
* @property string $codePath
|
||||
* @property string $description
|
||||
* @property string[] $keywords
|
||||
* @property ProjectVersion[] $versions
|
||||
* @property ProjectIntegrationType $projectIntegrationType
|
||||
* @property ProjectStats $projectStats
|
||||
*/
|
||||
final class ProjectHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return Project::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->active = (bool) ($data['active'] ?? true);
|
||||
$this->archived = (bool) ($data['archived'] ?? false);
|
||||
$this->name = (string) ($data['name'] ?? '');
|
||||
$this->shortName = (string) ($data['shortName'] ?? $this->name);
|
||||
$this->slug = (string) ($data['slug'] ?? '');
|
||||
$this->docsSlug = (string) ($data['docsSlug'] ?? $this->slug);
|
||||
$this->composerPackageName = (string) ($data['composerPackageName'] ?? '');
|
||||
$this->repositoryName = (string) ($data['repositoryName'] ?? '');
|
||||
$this->isIntegration = (bool) ($data['integration'] ?? false);
|
||||
$this->integrationFor = (string) ($data['integrationFor'] ?? '');
|
||||
$this->docsRepositoryName = (string) ($data['docsRepositoryName'] ?? $this->repositoryName);
|
||||
$this->docsPath = (string) ($data['docsPath'] ?? '/docs');
|
||||
$this->codePath = (string) ($data['codePath'] ?? '/lib');
|
||||
$this->description = (string) ($data['description'] ?? '');
|
||||
$this->keywords = $data['keywords'] ?? [];
|
||||
|
||||
if (! isset($data['versions'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$versions = [];
|
||||
|
||||
foreach ($data['versions'] as $version) {
|
||||
$versions[] = $version instanceof ProjectVersion
|
||||
? $version
|
||||
: new ProjectVersion($version);
|
||||
}
|
||||
|
||||
$this->versions = $versions;
|
||||
|
||||
if ($this->isIntegration) {
|
||||
$this->projectIntegrationType = new ProjectIntegrationType($data['integrationType']);
|
||||
}
|
||||
|
||||
$this->projectStats = new ProjectStats(
|
||||
(int) ($data['packagistData']['package']['github_stars'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['github_watchers'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['github_forks'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['github_open_issues'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['dependents'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['suggesters'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['downloads']['total'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['downloads']['monthly'] ?? 0),
|
||||
(int) ($data['packagistData']['package']['downloads']['daily'] ?? 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
29
lib/Hydrators/SitemapPageHydrator.php
Normal file
29
lib/Hydrators/SitemapPageHydrator.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Website\Model\SitemapPage;
|
||||
|
||||
/**
|
||||
* @property string $url
|
||||
* @property DateTimeImmutable $date
|
||||
*/
|
||||
final class SitemapPageHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return SitemapPage::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->url = (string) ($sitemapPage['url'] ?? '');
|
||||
$this->date = $sitemapPage['date'] ?? new DateTimeImmutable();
|
||||
}
|
||||
}
|
||||
45
lib/Hydrators/SponsorHydrator.php
Normal file
45
lib/Hydrators/SponsorHydrator.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Doctrine\Website\Model\Sponsor;
|
||||
use Doctrine\Website\Model\UtmParameters;
|
||||
use function array_merge;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $url
|
||||
* @property UtmParameters $utmParameters
|
||||
* @property bool $highlighted
|
||||
*/
|
||||
final class SponsorHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return Sponsor::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->name = (string) ($data['name'] ?? '');
|
||||
$this->url = (string) ($data['url'] ?? '');
|
||||
|
||||
$this->utmParameters = new UtmParameters(
|
||||
array_merge(
|
||||
[
|
||||
'utm_source' => 'doctrine',
|
||||
'utm_medium' => 'website',
|
||||
'utm_campaign' => 'sponsors',
|
||||
],
|
||||
$data['utmParameters'] ?? []
|
||||
)
|
||||
);
|
||||
|
||||
$this->highlighted = (bool) ($data['highlighted'] ?? '');
|
||||
}
|
||||
}
|
||||
57
lib/Hydrators/TeamMemberHydrator.php
Normal file
57
lib/Hydrators/TeamMemberHydrator.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Hydrators;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\Website\Model\Contributor;
|
||||
use Doctrine\Website\Model\TeamMember;
|
||||
use Doctrine\Website\Repositories\ContributorRepository;
|
||||
use function assert;
|
||||
|
||||
/**
|
||||
* @property string $name
|
||||
* @property string $github
|
||||
* @property string $twitter
|
||||
* @property string $avatarUrl
|
||||
* @property string $website
|
||||
* @property string $location
|
||||
* @property string[] $maintains
|
||||
* @property bool $consultant
|
||||
* @property string $headshot
|
||||
* @property string $bio
|
||||
* @property Closure|Contributor $contributor
|
||||
*/
|
||||
final class TeamMemberHydrator extends ModelHydrator
|
||||
{
|
||||
protected function getClassName() : string
|
||||
{
|
||||
return TeamMember::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $data
|
||||
*/
|
||||
protected function doHydrate(array $data) : void
|
||||
{
|
||||
$this->name = (string) ($data['name'] ?? '');
|
||||
$this->github = (string) ($data['github'] ?? '');
|
||||
$this->twitter = (string) ($data['twitter'] ?? '');
|
||||
$this->avatarUrl = (string) ($data['avatarUrl'] ?? '');
|
||||
$this->website = (string) ($data['website'] ?? '');
|
||||
$this->location = (string) ($data['location'] ?? '');
|
||||
$this->maintains = $data['maintains'] ?? [];
|
||||
$this->consultant = (bool) ($data['consultant'] ?? false);
|
||||
$this->headshot = (string) ($data['headshot'] ?? '');
|
||||
$this->bio = (string) ($data['bio'] ?? '');
|
||||
$this->contributor = function (string $github) : Contributor {
|
||||
$contributorRepository = $this->objectManager
|
||||
->getRepository(Contributor::class);
|
||||
|
||||
assert($contributorRepository instanceof ContributorRepository);
|
||||
|
||||
return $contributorRepository->findOneByGithub($github);
|
||||
};
|
||||
}
|
||||
}
|
||||
29
lib/Migrations/Version20190515005142.php
Normal file
29
lib/Migrations/Version20190515005142.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20190515005142 extends AbstractMigration
|
||||
{
|
||||
public function getDescription() : string
|
||||
{
|
||||
return 'Create event_participants table.';
|
||||
}
|
||||
|
||||
public function up(Schema $schema) : void
|
||||
{
|
||||
$this->addSql('CREATE TABLE event_participants (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(255) NOT NULL, quantity INT NOT NULL, eventId INT NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB');
|
||||
}
|
||||
|
||||
public function down(Schema $schema) : void
|
||||
{
|
||||
$this->addSql('DROP TABLE event_participants');
|
||||
}
|
||||
}
|
||||
87
lib/Model/Address.php
Normal file
87
lib/Model/Address.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class Address
|
||||
{
|
||||
/** @var string */
|
||||
private $line1;
|
||||
|
||||
/** @var string */
|
||||
private $line2;
|
||||
|
||||
/** @var string */
|
||||
private $city;
|
||||
|
||||
/** @var string */
|
||||
private $state;
|
||||
|
||||
/** @var string */
|
||||
private $zipCode;
|
||||
|
||||
/** @var string */
|
||||
private $countryCode;
|
||||
|
||||
public function __construct(
|
||||
string $line1,
|
||||
string $line2,
|
||||
string $city,
|
||||
string $state,
|
||||
string $zipCode,
|
||||
string $countryCode
|
||||
) {
|
||||
$this->line1 = $line1;
|
||||
$this->line2 = $line2;
|
||||
$this->city = $city;
|
||||
$this->state = $state;
|
||||
$this->zipCode = $zipCode;
|
||||
$this->countryCode = $countryCode;
|
||||
}
|
||||
|
||||
public function getLine1() : string
|
||||
{
|
||||
return $this->line1;
|
||||
}
|
||||
|
||||
public function getLine2() : string
|
||||
{
|
||||
return $this->line2;
|
||||
}
|
||||
|
||||
public function getCity() : string
|
||||
{
|
||||
return $this->city;
|
||||
}
|
||||
|
||||
public function getState() : string
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function getZipCode() : string
|
||||
{
|
||||
return $this->zipCode;
|
||||
}
|
||||
|
||||
public function getCountryCode() : string
|
||||
{
|
||||
return $this->countryCode;
|
||||
}
|
||||
|
||||
public function getString() : string
|
||||
{
|
||||
return sprintf(
|
||||
'%s %s %s, %s %s %s',
|
||||
$this->line1,
|
||||
$this->line2,
|
||||
$this->city,
|
||||
$this->state,
|
||||
$this->zipCode,
|
||||
$this->countryCode
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,10 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
|
||||
class BlogPost implements HydratableInterface, LoadMetadataInterface
|
||||
class BlogPost implements LoadMetadataInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $url;
|
||||
@@ -56,20 +54,6 @@ class BlogPost implements HydratableInterface, LoadMetadataInterface
|
||||
$metadata->setIdentifier(['slug']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $project
|
||||
*/
|
||||
public function hydrate(array $project, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->url = (string) $project['url'] ?? '';
|
||||
$this->slug = (string) $project['slug'] ?? '';
|
||||
$this->title = (string) $project['title'] ?? '';
|
||||
$this->authorName = (string) $project['authorName'] ?? '';
|
||||
$this->authorEmail = (string) $project['authorEmail'] ?? '';
|
||||
$this->contents = (string) $project['contents'] ?? '';
|
||||
$this->date = $project['date'] ?? new DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
{
|
||||
return $this->url;
|
||||
|
||||
@@ -4,12 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
|
||||
class Contributor implements HydratableInterface, LoadMetadataInterface, CommitterStats
|
||||
class Contributor implements LoadMetadataInterface, CommitterStats
|
||||
{
|
||||
/** @var TeamMember|null */
|
||||
private $teamMember;
|
||||
@@ -37,20 +35,6 @@ class Contributor implements HydratableInterface, LoadMetadataInterface, Committ
|
||||
$metadata->setIdentifier(['github']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $contributor
|
||||
*/
|
||||
public function hydrate(array $contributor, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->teamMember = $contributor['teamMember'] ?? null;
|
||||
$this->github = (string) ($contributor['github'] ?? '');
|
||||
$this->avatarUrl = (string) ($contributor['avatarUrl'] ?? '');
|
||||
$this->numCommits = (int) ($contributor['numCommits'] ?? 0);
|
||||
$this->numAdditions = (int) ($contributor['numAdditions'] ?? 0);
|
||||
$this->numDeletions = (int) ($contributor['numDeletions'] ?? 0);
|
||||
$this->projects = $contributor['projects'] ?? [];
|
||||
}
|
||||
|
||||
public function getTeamMember() : ?TeamMember
|
||||
{
|
||||
return $this->teamMember;
|
||||
|
||||
109
lib/Model/DateTimeRange.php
Normal file
109
lib/Model/DateTimeRange.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
final class DateTimeRange
|
||||
{
|
||||
/** @var DateTimeImmutable */
|
||||
private $start;
|
||||
|
||||
/** @var DateTimeImmutable */
|
||||
private $end;
|
||||
|
||||
/** @var DateTimeImmutable */
|
||||
private $now;
|
||||
|
||||
public function __construct(
|
||||
DateTimeImmutable $start,
|
||||
DateTimeImmutable $end,
|
||||
?DateTimeImmutable $now = null
|
||||
) {
|
||||
$this->start = $start;
|
||||
$this->end = $end;
|
||||
$this->now = $now ?? new DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getStart() : DateTimeImmutable
|
||||
{
|
||||
return $this->start;
|
||||
}
|
||||
|
||||
public function getEnd() : DateTimeImmutable
|
||||
{
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
public function isNow() : bool
|
||||
{
|
||||
return $this->start <= $this->now
|
||||
&& $this->end > $this->now;
|
||||
}
|
||||
|
||||
public function isOver() : bool
|
||||
{
|
||||
return $this->end < $this->now;
|
||||
}
|
||||
|
||||
public function isUpcoming() : bool
|
||||
{
|
||||
return $this->start > $this->now;
|
||||
}
|
||||
|
||||
public function getNumDays() : int
|
||||
{
|
||||
$days = (int) $this->end
|
||||
->diff($this->start)
|
||||
->days;
|
||||
|
||||
if ($days > 0) {
|
||||
return $days + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getNumHours() : int
|
||||
{
|
||||
$diff = $this->end->diff($this->start);
|
||||
|
||||
$numDays = $this->getNumDays();
|
||||
|
||||
if ($numDays === 1) {
|
||||
return $diff->h;
|
||||
}
|
||||
|
||||
return $diff->h + ($this->getNumDays() * 24);
|
||||
}
|
||||
|
||||
public function getNumMinutes() : int
|
||||
{
|
||||
$diff = $this->end->diff($this->start);
|
||||
|
||||
$minutes = $diff->days * 24 * 60;
|
||||
$minutes += $diff->h * 60;
|
||||
$minutes += $diff->i;
|
||||
|
||||
return (int) $minutes;
|
||||
}
|
||||
|
||||
public function getDuration() : string
|
||||
{
|
||||
$numDays = $this->getNumDays();
|
||||
|
||||
if ($numDays === 0) {
|
||||
$numMinutes = $this->getNumMinutes();
|
||||
|
||||
if ($numMinutes >= 60) {
|
||||
return $this->getNumHours() . '-hour';
|
||||
}
|
||||
|
||||
return $numMinutes . '-minute';
|
||||
}
|
||||
|
||||
return $this->getNumDays() . '-day';
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
|
||||
class DoctrineUser implements HydratableInterface, LoadMetadataInterface
|
||||
class DoctrineUser implements LoadMetadataInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
@@ -22,15 +20,6 @@ class DoctrineUser implements HydratableInterface, LoadMetadataInterface
|
||||
$metadata->setIdentifier(['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $doctrineUser
|
||||
*/
|
||||
public function hydrate(array $doctrineUser, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->name = (string) $doctrineUser['name'];
|
||||
$this->url = (string) $doctrineUser['url'];
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
|
||||
65
lib/Model/Entity/EventParticipant.php
Normal file
65
lib/Model/Entity/EventParticipant.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model\Entity;
|
||||
|
||||
use Doctrine\Website\Model\Event;
|
||||
|
||||
/**
|
||||
* @Entity(repositoryClass="EventParticipantRepository")
|
||||
* @Table(name="event_participants")
|
||||
*/
|
||||
final class EventParticipant
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
* @Id @Column(type="integer") @GeneratedValue
|
||||
**/
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @Column(type="string")
|
||||
**/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Column(type="integer")
|
||||
**/
|
||||
private $quantity;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
* @Column(type="integer")
|
||||
**/
|
||||
private $eventId;
|
||||
|
||||
public function __construct(Event $event, string $email, int $quantity)
|
||||
{
|
||||
$this->eventId = $event->getId();
|
||||
$this->email = $email;
|
||||
$this->quantity = $quantity;
|
||||
}
|
||||
|
||||
public function getId() : ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getEmail() : string
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
|
||||
public function getQuantity() : int
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
public function getEventId() : int
|
||||
{
|
||||
return $this->eventId;
|
||||
}
|
||||
}
|
||||
29
lib/Model/Entity/EventParticipantRepository.php
Normal file
29
lib/Model/Entity/EventParticipantRepository.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model\Entity;
|
||||
|
||||
use Doctrine\ORM\EntityRepository;
|
||||
|
||||
final class EventParticipantRepository extends EntityRepository
|
||||
{
|
||||
public function findOneByEmail(string $email) : ?EventParticipant
|
||||
{
|
||||
/** @var EventParticipant $eventParticipant */
|
||||
$eventParticipant = $this->findOneBy(['email' => $email]);
|
||||
|
||||
return $eventParticipant;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return EventParticipant[]
|
||||
*/
|
||||
public function findByEventId(int $eventId) : array
|
||||
{
|
||||
/** @var EventParticipant[] $eventParticipants */
|
||||
$eventParticipants = $this->findBy(['eventId' => $eventId]);
|
||||
|
||||
return $eventParticipants;
|
||||
}
|
||||
}
|
||||
165
lib/Model/Event.php
Normal file
165
lib/Model/Event.php
Normal file
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
|
||||
final class Event implements LoadMetadataInterface
|
||||
{
|
||||
/** @var int */
|
||||
private $id;
|
||||
|
||||
/** @var string */
|
||||
private $type;
|
||||
|
||||
/** @var string */
|
||||
private $sku;
|
||||
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var string */
|
||||
private $slug;
|
||||
|
||||
/** @var string */
|
||||
private $joinUrl;
|
||||
|
||||
/** @var DateTimeRange */
|
||||
private $dateTimeRange;
|
||||
|
||||
/** @var DateTimeRange */
|
||||
private $registrationDateTimeRange;
|
||||
|
||||
/** @var EventCfp */
|
||||
private $cfp;
|
||||
|
||||
/** @var EventLocation|null */
|
||||
private $location;
|
||||
|
||||
/** @var EventSponsors */
|
||||
private $sponsors;
|
||||
|
||||
/** @var EventSpeakers */
|
||||
private $speakers;
|
||||
|
||||
/** @var EventSchedule */
|
||||
private $schedule;
|
||||
|
||||
/** @var EventParticipants */
|
||||
private $participants;
|
||||
|
||||
/** @var string */
|
||||
private $description;
|
||||
|
||||
/** @var float */
|
||||
private $price;
|
||||
|
||||
public static function loadMetadata(ClassMetadataInterface $metadata) : void
|
||||
{
|
||||
$metadata->setIdentifier(['id']);
|
||||
}
|
||||
|
||||
public function getId() : int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function isWebinar() : bool
|
||||
{
|
||||
return $this->type === EventType::WEBINAR;
|
||||
}
|
||||
|
||||
public function isConference() : bool
|
||||
{
|
||||
return $this->type === EventType::CONFERENCE;
|
||||
}
|
||||
|
||||
public function getSku() : string
|
||||
{
|
||||
return $this->sku;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getSlug() : string
|
||||
{
|
||||
return $this->slug;
|
||||
}
|
||||
|
||||
public function getJoinUrl() : string
|
||||
{
|
||||
return $this->joinUrl;
|
||||
}
|
||||
|
||||
public function getDates() : DateTimeRange
|
||||
{
|
||||
return $this->dateTimeRange;
|
||||
}
|
||||
|
||||
public function getRegistrationDates() : DateTimeRange
|
||||
{
|
||||
return $this->registrationDateTimeRange;
|
||||
}
|
||||
|
||||
public function getStartDate() : DateTimeImmutable
|
||||
{
|
||||
return $this->dateTimeRange->getStart();
|
||||
}
|
||||
|
||||
public function getEndDate() : DateTimeImmutable
|
||||
{
|
||||
return $this->dateTimeRange->getEnd();
|
||||
}
|
||||
|
||||
public function getCfp() : EventCfp
|
||||
{
|
||||
return $this->cfp;
|
||||
}
|
||||
|
||||
public function getLocation() : ?EventLocation
|
||||
{
|
||||
return $this->location;
|
||||
}
|
||||
|
||||
public function getSponsors() : EventSponsors
|
||||
{
|
||||
return $this->sponsors;
|
||||
}
|
||||
|
||||
public function getSpeakers() : EventSpeakers
|
||||
{
|
||||
return $this->speakers;
|
||||
}
|
||||
|
||||
public function getSchedule() : EventSchedule
|
||||
{
|
||||
return $this->schedule;
|
||||
}
|
||||
|
||||
public function getParticipants() : EventParticipants
|
||||
{
|
||||
return $this->participants;
|
||||
}
|
||||
|
||||
public function getDescription() : string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function getPrice() : float
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
|
||||
public function isFree() : bool
|
||||
{
|
||||
return $this->price === 0.00;
|
||||
}
|
||||
}
|
||||
47
lib/Model/EventCfp.php
Normal file
47
lib/Model/EventCfp.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use LogicException;
|
||||
use function sprintf;
|
||||
|
||||
final class EventCfp
|
||||
{
|
||||
/** @var string */
|
||||
private $googleFormId;
|
||||
|
||||
/** @var DateTimeRange */
|
||||
private $dateTimeRange;
|
||||
|
||||
public function __construct(string $googleFormId, DateTimeRange $dateTimeRange)
|
||||
{
|
||||
$this->googleFormId = $googleFormId;
|
||||
$this->dateTimeRange = $dateTimeRange;
|
||||
}
|
||||
|
||||
public function exists() : bool
|
||||
{
|
||||
return $this->googleFormId !== '';
|
||||
}
|
||||
|
||||
public function getGoogleFormUrl() : string
|
||||
{
|
||||
if (! $this->exists()) {
|
||||
throw new LogicException('Cannot call EventCfp::getGoogleFormUrl() when no googleFormId is set.');
|
||||
}
|
||||
|
||||
return sprintf('https://docs.google.com/forms/d/e/%s/viewform', $this->googleFormId);
|
||||
}
|
||||
|
||||
public function getEmbeddedGoogleFormUrl() : string
|
||||
{
|
||||
return sprintf('%s?embedded=true', $this->getGoogleFormUrl());
|
||||
}
|
||||
|
||||
public function getDates() : DateTimeRange
|
||||
{
|
||||
return $this->dateTimeRange;
|
||||
}
|
||||
}
|
||||
30
lib/Model/EventLocation.php
Normal file
30
lib/Model/EventLocation.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
final class EventLocation
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var Address */
|
||||
private $address;
|
||||
|
||||
public function __construct(string $name, Address $address)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->address = $address;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getAddress() : Address
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
}
|
||||
32
lib/Model/EventParticipants.php
Normal file
32
lib/Model/EventParticipants.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Website\Model\Entity\EventParticipantRepository;
|
||||
|
||||
final class EventParticipants extends AbstractLazyCollection
|
||||
{
|
||||
/** @var int */
|
||||
private $eventId;
|
||||
|
||||
/** @var EventParticipantRepository */
|
||||
private $eventParticipantRepository;
|
||||
|
||||
public function __construct(int $eventId, EventParticipantRepository $eventParticipantRepository)
|
||||
{
|
||||
$this->eventId = $eventId;
|
||||
$this->eventParticipantRepository = $eventParticipantRepository;
|
||||
}
|
||||
|
||||
protected function doInitialize() : void
|
||||
{
|
||||
$eventParticipants = $this->eventParticipantRepository
|
||||
->findByEventId($this->eventId);
|
||||
|
||||
$this->collection = new ArrayCollection($eventParticipants);
|
||||
}
|
||||
}
|
||||
53
lib/Model/EventSchedule.php
Normal file
53
lib/Model/EventSchedule.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use InvalidArgumentException;
|
||||
use function sprintf;
|
||||
|
||||
final class EventSchedule extends AbstractLazyCollection
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private $event;
|
||||
|
||||
/** @var EventSpeakers */
|
||||
private $speakers;
|
||||
|
||||
/**
|
||||
* @param mixed[] $event
|
||||
*/
|
||||
public function __construct(array $event, EventSpeakers $speakers)
|
||||
{
|
||||
$this->event = $event;
|
||||
$this->speakers = $speakers;
|
||||
}
|
||||
|
||||
protected function doInitialize() : void
|
||||
{
|
||||
$slots = [];
|
||||
|
||||
foreach ($this->event['schedule'] as $slot) {
|
||||
if (! isset($this->speakers[$slot['topicSlug']])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Could not find speaker with topicSlug "%s".',
|
||||
$slot['topicSlug']
|
||||
));
|
||||
}
|
||||
|
||||
$eventSpeaker = $this->speakers[$slot['topicSlug']];
|
||||
|
||||
$slots[] = new EventScheduleSlot(
|
||||
$eventSpeaker,
|
||||
new DateTimeImmutable($slot['startDate'] ?? ''),
|
||||
new DateTimeImmutable($slot['endDate'] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
$this->collection = new ArrayCollection($slots);
|
||||
}
|
||||
}
|
||||
44
lib/Model/EventScheduleSlot.php
Normal file
44
lib/Model/EventScheduleSlot.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
final class EventScheduleSlot
|
||||
{
|
||||
/** @var EventSpeaker */
|
||||
private $speaker;
|
||||
|
||||
/** @var DateTimeImmutable */
|
||||
private $startDate;
|
||||
|
||||
/** @var DateTimeImmutable */
|
||||
private $endDate;
|
||||
|
||||
public function __construct(
|
||||
EventSpeaker $speaker,
|
||||
DateTimeImmutable $startDate,
|
||||
DateTimeImmutable $endDate
|
||||
) {
|
||||
$this->speaker = $speaker;
|
||||
$this->startDate = $startDate;
|
||||
$this->endDate = $endDate;
|
||||
}
|
||||
|
||||
public function getSpeaker() : EventSpeaker
|
||||
{
|
||||
return $this->speaker;
|
||||
}
|
||||
|
||||
public function getStartDate() : DateTimeImmutable
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
public function getEndDate() : DateTimeImmutable
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
}
|
||||
84
lib/Model/EventSpeaker.php
Normal file
84
lib/Model/EventSpeaker.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class EventSpeaker
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var string */
|
||||
private $avatarUrl;
|
||||
|
||||
/** @var string */
|
||||
private $topic;
|
||||
|
||||
/** @var string */
|
||||
private $topicSlug;
|
||||
|
||||
/** @var string */
|
||||
private $description;
|
||||
|
||||
/** @var string */
|
||||
private $youTubeVideoId;
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $avatarUrl,
|
||||
string $topic,
|
||||
string $topicSlug,
|
||||
string $description,
|
||||
string $youTubeVideoId
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->avatarUrl = $avatarUrl;
|
||||
$this->topic = $topic;
|
||||
$this->topicSlug = $topicSlug;
|
||||
$this->description = $description;
|
||||
$this->youTubeVideoId = $youTubeVideoId;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getAvatarUrl() : string
|
||||
{
|
||||
return $this->avatarUrl;
|
||||
}
|
||||
|
||||
public function getTopic() : string
|
||||
{
|
||||
return $this->topic;
|
||||
}
|
||||
|
||||
public function getTopicSlug() : string
|
||||
{
|
||||
return $this->topicSlug;
|
||||
}
|
||||
|
||||
public function getDescription() : string
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
public function hasYouTubeVideo() : bool
|
||||
{
|
||||
return $this->youTubeVideoId !== '';
|
||||
}
|
||||
|
||||
public function getYouTubeVideoId() : string
|
||||
{
|
||||
return $this->youTubeVideoId;
|
||||
}
|
||||
|
||||
public function getYouTubeUrl() : string
|
||||
{
|
||||
return sprintf('https://www.youtube.com/watch?v=%s', $this->youTubeVideoId);
|
||||
}
|
||||
}
|
||||
58
lib/Model/EventSpeakers.php
Normal file
58
lib/Model/EventSpeakers.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use Doctrine\Website\Repositories\TeamMemberRepository;
|
||||
use function assert;
|
||||
|
||||
final class EventSpeakers extends AbstractLazyCollection
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private $event;
|
||||
|
||||
/** @var ObjectManagerInterface */
|
||||
private $objectManager;
|
||||
|
||||
/**
|
||||
* @param mixed[] $event
|
||||
*/
|
||||
public function __construct(array $event, ObjectManagerInterface $objectManager)
|
||||
{
|
||||
$this->event = $event;
|
||||
$this->objectManager = $objectManager;
|
||||
}
|
||||
|
||||
protected function doInitialize() : void
|
||||
{
|
||||
$teamMemberRepository = $this->objectManager->getRepository(TeamMember::class);
|
||||
assert($teamMemberRepository instanceof TeamMemberRepository);
|
||||
|
||||
$speakers = [];
|
||||
|
||||
foreach ($this->event['speakers'] ?? [] as $speaker) {
|
||||
$speakerName = (string) ($speaker['name'] ?? '');
|
||||
|
||||
$teamMember = $speakerName !== ''
|
||||
? $teamMemberRepository->findOneByGithub($speakerName)
|
||||
: null;
|
||||
|
||||
$topicSlug = (string) ($speaker['topicSlug'] ?? '');
|
||||
|
||||
$speakers[$topicSlug] = new EventSpeaker(
|
||||
$teamMember !== null ? $teamMember->getName() : $speakerName,
|
||||
$teamMember !== null ? $teamMember->getAvatarUrl() : (string) ($speaker['avatarUrl'] ?? ''),
|
||||
(string) ($speaker['topic'] ?? ''),
|
||||
$topicSlug,
|
||||
(string) ($speaker['description'] ?? ''),
|
||||
(string) ($speaker['youTubeVideoId'] ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
$this->collection = new ArrayCollection($speakers);
|
||||
}
|
||||
}
|
||||
51
lib/Model/EventSponsor.php
Normal file
51
lib/Model/EventSponsor.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
final class EventSponsor
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var string */
|
||||
private $url;
|
||||
|
||||
/** @var string */
|
||||
private $logo;
|
||||
|
||||
/** @var UtmParameters */
|
||||
private $utmParameters;
|
||||
|
||||
public function __construct(string $name, string $url, string $logo, UtmParameters $utmParameters)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->url = $url;
|
||||
$this->logo = $logo;
|
||||
$this->utmParameters = $utmParameters;
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $parameters
|
||||
*/
|
||||
public function getUrlWithUtmParameters(array $parameters = []) : string
|
||||
{
|
||||
return $this->utmParameters->buildUrl($this->url, $parameters);
|
||||
}
|
||||
|
||||
public function getLogo() : string
|
||||
{
|
||||
return $this->logo;
|
||||
}
|
||||
}
|
||||
48
lib/Model/EventSponsors.php
Normal file
48
lib/Model/EventSponsors.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\Common\Collections\AbstractLazyCollection;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use function array_merge;
|
||||
|
||||
final class EventSponsors extends AbstractLazyCollection
|
||||
{
|
||||
/** @var mixed[] */
|
||||
private $event;
|
||||
|
||||
/**
|
||||
* @param mixed[] $event
|
||||
*/
|
||||
public function __construct(array $event)
|
||||
{
|
||||
$this->event = $event;
|
||||
}
|
||||
|
||||
protected function doInitialize() : void
|
||||
{
|
||||
$sponsors = [];
|
||||
|
||||
foreach ($this->event['sponsors'] ?? [] as $sponsor) {
|
||||
$sponsors[] = new EventSponsor(
|
||||
(string) ($sponsor['name'] ?? ''),
|
||||
(string) ($sponsor['url'] ?? ''),
|
||||
(string) ($sponsor['logo'] ?? ''),
|
||||
new UtmParameters(
|
||||
array_merge(
|
||||
[
|
||||
'utm_source' => 'doctrine',
|
||||
'utm_medium' => 'website',
|
||||
'utm_campaign' => $this->event['slug'],
|
||||
],
|
||||
$sponsor['utmParameters'] ?? []
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$this->collection = new ArrayCollection($sponsors);
|
||||
}
|
||||
}
|
||||
15
lib/Model/EventType.php
Normal file
15
lib/Model/EventType.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
final class EventType
|
||||
{
|
||||
public const WEBINAR = 'webinar';
|
||||
public const CONFERENCE = 'conference';
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use function array_merge;
|
||||
|
||||
final class Partner implements HydratableInterface, LoadMetadataInterface
|
||||
final class Partner implements LoadMetadataInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
@@ -41,33 +38,6 @@ final class Partner implements HydratableInterface, LoadMetadataInterface
|
||||
$metadata->setIdentifier(['slug']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $partner
|
||||
*/
|
||||
public function hydrate(array $partner, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->name = (string) ($partner['name'] ?? '');
|
||||
$this->slug = (string) ($partner['slug'] ?? '');
|
||||
$this->url = (string) ($partner['url'] ?? '');
|
||||
$this->utmParameters = new UtmParameters(
|
||||
array_merge(
|
||||
[
|
||||
'utm_source' => 'doctrine',
|
||||
'utm_medium' => 'website',
|
||||
'utm_campaign' => 'partners',
|
||||
],
|
||||
$partner['utmParameters'] ?? []
|
||||
)
|
||||
);
|
||||
$this->logo = (string) ($partner['logo'] ?? '');
|
||||
$this->bio = (string) ($partner['bio'] ?? '');
|
||||
$this->details = new PartnerDetails(
|
||||
(string) ($partner['details']['label'] ?? ''),
|
||||
$partner['details']['items'] ?? []
|
||||
);
|
||||
$this->featured = (bool) ($partner['featured'] ?? false);
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
|
||||
@@ -5,16 +5,14 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use InvalidArgumentException;
|
||||
use function array_filter;
|
||||
use function array_values;
|
||||
use function sprintf;
|
||||
|
||||
class Project implements HydratableInterface, LoadMetadataInterface
|
||||
class Project implements LoadMetadataInterface
|
||||
{
|
||||
/** @var ProjectIntegrationType|null */
|
||||
private $projectIntegrationType;
|
||||
@@ -70,75 +68,11 @@ class Project implements HydratableInterface, LoadMetadataInterface
|
||||
/** @var ProjectVersion[] */
|
||||
private $versions = [];
|
||||
|
||||
/**
|
||||
* @param mixed[] $project
|
||||
*/
|
||||
public function __construct(array $project)
|
||||
{
|
||||
$this->doHydrate($project);
|
||||
}
|
||||
|
||||
public static function loadMetadata(ClassMetadataInterface $metadata) : void
|
||||
{
|
||||
$metadata->setIdentifier(['slug']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $project
|
||||
*/
|
||||
public function hydrate(array $project, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->doHydrate($project);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $project
|
||||
*/
|
||||
public function doHydrate(array $project) : void
|
||||
{
|
||||
$this->active = (bool) ($project['active'] ?? true);
|
||||
$this->archived = (bool) ($project['archived'] ?? false);
|
||||
$this->name = (string) ($project['name'] ?? '');
|
||||
$this->shortName = (string) ($project['shortName'] ?? $this->name);
|
||||
$this->slug = (string) ($project['slug'] ?? '');
|
||||
$this->docsSlug = (string) ($project['docsSlug'] ?? $this->slug);
|
||||
$this->composerPackageName = (string) ($project['composerPackageName'] ?? '');
|
||||
$this->repositoryName = (string) ($project['repositoryName'] ?? '');
|
||||
$this->isIntegration = (bool) ($project['integration'] ?? false);
|
||||
$this->integrationFor = (string) ($project['integrationFor'] ?? '');
|
||||
$this->docsRepositoryName = (string) ($project['docsRepositoryName'] ?? $this->repositoryName);
|
||||
$this->docsPath = (string) ($project['docsPath'] ?? '/docs');
|
||||
$this->codePath = (string) ($project['codePath'] ?? '/lib');
|
||||
$this->description = (string) ($project['description'] ?? '');
|
||||
$this->keywords = $project['keywords'] ?? [];
|
||||
|
||||
if (! isset($project['versions'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($project['versions'] as $version) {
|
||||
$this->versions[] = $version instanceof ProjectVersion
|
||||
? $version
|
||||
: new ProjectVersion($version);
|
||||
}
|
||||
|
||||
if ($this->isIntegration) {
|
||||
$this->projectIntegrationType = new ProjectIntegrationType($project['integrationType']);
|
||||
}
|
||||
|
||||
$this->projectStats = new ProjectStats(
|
||||
(int) ($project['packagistData']['package']['github_stars'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['github_watchers'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['github_forks'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['github_open_issues'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['dependents'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['suggesters'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['downloads']['total'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['downloads']['monthly'] ?? 0),
|
||||
(int) ($project['packagistData']['package']['downloads']['daily'] ?? 0)
|
||||
);
|
||||
}
|
||||
|
||||
public function getProjectIntegrationType() : ?ProjectIntegrationType
|
||||
{
|
||||
return $this->projectIntegrationType;
|
||||
|
||||
@@ -4,12 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
|
||||
class ProjectContributor implements HydratableInterface, LoadMetadataInterface, CommitterStats
|
||||
class ProjectContributor implements LoadMetadataInterface, CommitterStats
|
||||
{
|
||||
/** @var TeamMember|null */
|
||||
private $teamMember;
|
||||
@@ -40,21 +38,6 @@ class ProjectContributor implements HydratableInterface, LoadMetadataInterface,
|
||||
$metadata->setIdentifier(['projectSlug', 'github']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $projectContributor
|
||||
*/
|
||||
public function hydrate(array $projectContributor, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->teamMember = $projectContributor['teamMember'] ?? null;
|
||||
$this->projectSlug = (string) ($projectContributor['projectSlug'] ?? '');
|
||||
$this->project = $projectContributor['project'] ?? new Project([]);
|
||||
$this->github = (string) ($projectContributor['github'] ?? '');
|
||||
$this->avatarUrl = (string) ($projectContributor['avatarUrl'] ?? '');
|
||||
$this->numCommits = (int) ($projectContributor['numCommits'] ?? 0);
|
||||
$this->numAdditions = (int) ($projectContributor['numAdditions'] ?? 0);
|
||||
$this->numDeletions = (int) ($projectContributor['numDeletions'] ?? 0);
|
||||
}
|
||||
|
||||
public function getTeamMember() : ?TeamMember
|
||||
{
|
||||
return $this->teamMember;
|
||||
|
||||
@@ -5,12 +5,10 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
|
||||
class SitemapPage implements HydratableInterface, LoadMetadataInterface
|
||||
class SitemapPage implements LoadMetadataInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $url;
|
||||
@@ -29,15 +27,6 @@ class SitemapPage implements HydratableInterface, LoadMetadataInterface
|
||||
$metadata->setIdentifier(['url']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sitemapPage
|
||||
*/
|
||||
public function hydrate(array $sitemapPage, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->url = (string) ($sitemapPage['url'] ?? '');
|
||||
$this->date = $sitemapPage['date'] ?? new DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getUrl() : string
|
||||
{
|
||||
return $this->url;
|
||||
|
||||
@@ -4,13 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use function array_merge;
|
||||
|
||||
final class Sponsor implements HydratableInterface, LoadMetadataInterface
|
||||
final class Sponsor implements LoadMetadataInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
@@ -29,26 +26,6 @@ final class Sponsor implements HydratableInterface, LoadMetadataInterface
|
||||
$metadata->setIdentifier(['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $sponsor
|
||||
*/
|
||||
public function hydrate(array $sponsor, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->name = (string) ($sponsor['name'] ?? '');
|
||||
$this->url = (string) ($sponsor['url'] ?? '');
|
||||
$this->utmParameters = new UtmParameters(
|
||||
array_merge(
|
||||
[
|
||||
'utm_source' => 'doctrine',
|
||||
'utm_medium' => 'website',
|
||||
'utm_campaign' => 'sponsors',
|
||||
],
|
||||
$sponsor['utmParameters'] ?? []
|
||||
)
|
||||
);
|
||||
$this->highlighted = (bool) ($sponsor['highlighted'] ?? '');
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
|
||||
@@ -5,15 +5,11 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Model;
|
||||
|
||||
use Closure;
|
||||
use Doctrine\SkeletonMapper\Hydrator\HydratableInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\ClassMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\Mapping\LoadMetadataInterface;
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use Doctrine\Website\Repositories\ContributorRepository;
|
||||
use function assert;
|
||||
use function in_array;
|
||||
|
||||
class TeamMember implements HydratableInterface, LoadMetadataInterface, CommitterStats
|
||||
class TeamMember implements LoadMetadataInterface, CommitterStats
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
@@ -53,31 +49,6 @@ class TeamMember implements HydratableInterface, LoadMetadataInterface, Committe
|
||||
$metadata->setIdentifier(['github']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed[] $teamMember
|
||||
*/
|
||||
public function hydrate(array $teamMember, ObjectManagerInterface $objectManager) : void
|
||||
{
|
||||
$this->name = (string) ($teamMember['name'] ?? '');
|
||||
$this->github = (string) ($teamMember['github'] ?? '');
|
||||
$this->twitter = (string) ($teamMember['twitter'] ?? '');
|
||||
$this->avatarUrl = (string) ($teamMember['avatarUrl'] ?? '');
|
||||
$this->website = (string) ($teamMember['website'] ?? '');
|
||||
$this->location = (string) ($teamMember['location'] ?? '');
|
||||
$this->maintains = $teamMember['maintains'] ?? [];
|
||||
$this->consultant = (bool) ($teamMember['consultant'] ?? false);
|
||||
$this->headshot = (string) ($teamMember['headshot'] ?? '');
|
||||
$this->bio = (string) ($teamMember['bio'] ?? '');
|
||||
$this->contributor = static function (string $github) use ($objectManager) : Contributor {
|
||||
$contributorRepository = $objectManager
|
||||
->getRepository(Contributor::class);
|
||||
|
||||
assert($contributorRepository instanceof ContributorRepository);
|
||||
|
||||
return $contributorRepository->findOneByGithub($github);
|
||||
};
|
||||
}
|
||||
|
||||
public function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
|
||||
55
lib/Repositories/EventRepository.php
Normal file
55
lib/Repositories/EventRepository.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Repositories;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Criteria;
|
||||
use Doctrine\SkeletonMapper\ObjectRepository\BasicObjectRepository;
|
||||
use Doctrine\Website\Model\Event;
|
||||
use InvalidArgumentException;
|
||||
use function sprintf;
|
||||
|
||||
class EventRepository extends BasicObjectRepository
|
||||
{
|
||||
public function findOneById(int $id) : Event
|
||||
{
|
||||
$event = $this->findOneBy(['id' => $id]);
|
||||
|
||||
if ($event === null) {
|
||||
throw new InvalidArgumentException(sprintf('Could not find Event with id "%s"', $id));
|
||||
}
|
||||
|
||||
return $event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Event[]
|
||||
*/
|
||||
public function findUpcomingEvents() : array
|
||||
{
|
||||
/** @var Event[] $events */
|
||||
$events = $this->findBy([], ['startDate' => 'asc']);
|
||||
|
||||
$criteria = Criteria::create()
|
||||
->where(Criteria::expr()->gt('startDate', new DateTimeImmutable()));
|
||||
|
||||
return (new ArrayCollection($events))->matching($criteria)->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Event[]
|
||||
*/
|
||||
public function findPastEvents() : array
|
||||
{
|
||||
/** @var Event[] $events */
|
||||
$events = $this->findBy([], ['endDate' => 'desc']);
|
||||
|
||||
$criteria = Criteria::create()
|
||||
->where(Criteria::expr()->lt('endDate', new DateTimeImmutable()));
|
||||
|
||||
return (new ArrayCollection($events))->matching($criteria)->toArray();
|
||||
}
|
||||
}
|
||||
38
lib/Requests/EventRequests.php
Normal file
38
lib/Requests/EventRequests.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Requests;
|
||||
|
||||
use Doctrine\StaticWebsiteGenerator\Request\ArrayRequestCollection;
|
||||
use Doctrine\StaticWebsiteGenerator\Request\RequestCollection;
|
||||
use Doctrine\Website\Model\Event;
|
||||
use Doctrine\Website\Repositories\EventRepository;
|
||||
|
||||
class EventRequests
|
||||
{
|
||||
/** @var EventRepository */
|
||||
private $eventRepository;
|
||||
|
||||
public function __construct(EventRepository $eventRepository)
|
||||
{
|
||||
$this->eventRepository = $eventRepository;
|
||||
}
|
||||
|
||||
public function getEvents() : RequestCollection
|
||||
{
|
||||
/** @var Event[] $events */
|
||||
$events = $this->eventRepository->findAll();
|
||||
|
||||
$requests = [];
|
||||
|
||||
foreach ($events as $event) {
|
||||
$requests[] = [
|
||||
'id' => $event->getId(),
|
||||
'slug' => $event->getSlug(),
|
||||
];
|
||||
}
|
||||
|
||||
return new ArrayRequestCollection($requests);
|
||||
}
|
||||
}
|
||||
44
lib/Site.php
Normal file
44
lib/Site.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website;
|
||||
|
||||
use Doctrine\StaticWebsiteGenerator\Site as BaseSite;
|
||||
|
||||
final class Site extends BaseSite
|
||||
{
|
||||
/** @var string */
|
||||
private $assetsUrl;
|
||||
|
||||
/**
|
||||
* @param string[] $keywords
|
||||
*/
|
||||
public function __construct(
|
||||
string $title,
|
||||
string $subtitle,
|
||||
string $url,
|
||||
array $keywords,
|
||||
string $description,
|
||||
string $env,
|
||||
string $googleAnalyticsTrackingId,
|
||||
string $assetsUrl
|
||||
) {
|
||||
parent::__construct(
|
||||
$title,
|
||||
$subtitle,
|
||||
$url,
|
||||
$keywords,
|
||||
$description,
|
||||
$env,
|
||||
$googleAnalyticsTrackingId
|
||||
);
|
||||
|
||||
$this->assetsUrl = $assetsUrl;
|
||||
}
|
||||
|
||||
public function getAssetsUrl() : string
|
||||
{
|
||||
return $this->assetsUrl;
|
||||
}
|
||||
}
|
||||
@@ -36,12 +36,21 @@ class MainExtension extends Twig_Extension
|
||||
/** @var string */
|
||||
private $webpackBuildDir;
|
||||
|
||||
public function __construct(Parsedown $parsedown, AssetIntegrityGenerator $assetIntegrityGenerator, string $sourceDir, string $webpackBuildDir)
|
||||
{
|
||||
/** @var string */
|
||||
private $stripePublishableKey;
|
||||
|
||||
public function __construct(
|
||||
Parsedown $parsedown,
|
||||
AssetIntegrityGenerator $assetIntegrityGenerator,
|
||||
string $sourceDir,
|
||||
string $webpackBuildDir,
|
||||
string $stripePublishableKey
|
||||
) {
|
||||
$this->parsedown = $parsedown;
|
||||
$this->assetIntegrityGenerator = $assetIntegrityGenerator;
|
||||
$this->sourceDir = $sourceDir;
|
||||
$this->webpackBuildDir = $webpackBuildDir;
|
||||
$this->stripePublishableKey = $stripePublishableKey;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -55,6 +64,7 @@ class MainExtension extends Twig_Extension
|
||||
new Twig_SimpleFunction('get_webpack_asset_url', [$this, 'getWebpackAssetUrl']),
|
||||
new Twig_SimpleFunction('get_asset_integrity', [$this->assetIntegrityGenerator, 'getAssetIntegrity']),
|
||||
new Twig_SimpleFunction('get_webpack_asset_integrity', [$this->assetIntegrityGenerator, 'getWebpackAssetIntegrity']),
|
||||
new Twig_SimpleFunction('get_stripe_publishable_key', [$this, 'getStripePublishableKey']),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -108,6 +118,11 @@ class MainExtension extends Twig_Extension
|
||||
return $string;
|
||||
}
|
||||
|
||||
public function getStripePublishableKey() : string
|
||||
{
|
||||
return $this->stripePublishableKey;
|
||||
}
|
||||
|
||||
private function getAssetCacheBuster(string $path, string $rootPath) : string
|
||||
{
|
||||
$assetPath = realpath($rootPath . '/' . $path);
|
||||
|
||||
@@ -15,6 +15,7 @@ use Symfony\Component\Filesystem\Filesystem;
|
||||
use function chdir;
|
||||
use function file_exists;
|
||||
use function file_put_contents;
|
||||
use function getcwd;
|
||||
use function glob;
|
||||
use function in_array;
|
||||
use function is_dir;
|
||||
@@ -108,7 +109,7 @@ class WebsiteBuilder
|
||||
|
||||
$this->createProjectVersionAliases($buildDir);
|
||||
|
||||
$this->copyWebsiteBuildData($buildDir);
|
||||
$this->copyWebsiteBuildData($output, $buildDir);
|
||||
|
||||
if ($publish) {
|
||||
$output->writeln(' - publishing build');
|
||||
@@ -129,27 +130,38 @@ class WebsiteBuilder
|
||||
*/
|
||||
private function buildWebsite(OutputInterface $output, string $buildDir, bool $isPublishableEnv) : void
|
||||
{
|
||||
$output->writeln(sprintf(' - clearing build directory <info>%s</info>', $buildDir));
|
||||
|
||||
// cleanup the build directory
|
||||
$this->filesystem->remove(glob($buildDir . '/*'));
|
||||
|
||||
// Move webpack assets into build directory
|
||||
$this->buildWebpackAssets($output, $buildDir, $isPublishableEnv);
|
||||
|
||||
$this->sourceFilesBuilder->buildSourceFiles(
|
||||
$this->sourceFileRepository->getSourceFiles($buildDir)
|
||||
);
|
||||
$output->writeln(' - calculating source files to build');
|
||||
|
||||
$sourceFiles = $this->sourceFileRepository->getSourceFiles($buildDir);
|
||||
|
||||
$output->writeln(sprintf(' - building source files to <info>%s</info>', $buildDir));
|
||||
|
||||
$this->sourceFilesBuilder->buildSourceFiles($sourceFiles);
|
||||
}
|
||||
|
||||
private function buildWebpackAssets(OutputInterface $output, string $buildDir, bool $isPublishableEnv) : void
|
||||
{
|
||||
$output->writeln(sprintf(' - running npm run %s ', $isPublishableEnv ? 'build' : 'dev'));
|
||||
$output->writeln(sprintf(' - running <info>npm run %s</info> ', $isPublishableEnv ? 'build' : 'dev'));
|
||||
|
||||
$this->filesystem->remove(glob($this->webpackBuildDir . '/*'));
|
||||
|
||||
$process = $this->processFactory->run(sprintf(
|
||||
'cd %s && npm run %s',
|
||||
$this->rootDir,
|
||||
$isPublishableEnv ? 'build' : 'dev'
|
||||
));
|
||||
$output->write($process->getOutput());
|
||||
|
||||
if ($output->isVerbose()) {
|
||||
$output->write($process->getOutput());
|
||||
}
|
||||
|
||||
// Copy built assets if this is a publishable build
|
||||
if ($isPublishableEnv) {
|
||||
@@ -181,9 +193,18 @@ class WebsiteBuilder
|
||||
}
|
||||
}
|
||||
|
||||
private function copyWebsiteBuildData(string $buildDir) : void
|
||||
private function copyWebsiteBuildData(OutputInterface $output, string $buildDir) : void
|
||||
{
|
||||
$this->filesystem->mirror($this->cacheDir . '/data', $buildDir . '/website-data');
|
||||
$from = $this->cacheDir . '/data';
|
||||
$to = $buildDir . '/website-data';
|
||||
|
||||
$output->writeln(sprintf(
|
||||
' - copying website build data from <info>%s</info> to <info>%s</info>.',
|
||||
$from,
|
||||
$to
|
||||
));
|
||||
|
||||
$this->filesystem->mirror($from, $to);
|
||||
}
|
||||
|
||||
private function createDocsProjectVersionAlias(
|
||||
@@ -207,16 +228,22 @@ class WebsiteBuilder
|
||||
return;
|
||||
}
|
||||
|
||||
$cwd = getcwd();
|
||||
|
||||
chdir($dir);
|
||||
|
||||
if (file_exists($alias)) {
|
||||
unlink($alias);
|
||||
}
|
||||
|
||||
if (! file_exists($version->getSlug())) {
|
||||
if (file_exists($version->getSlug())) {
|
||||
symlink($version->getSlug(), $alias);
|
||||
}
|
||||
|
||||
if ($cwd === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
symlink($version->getSlug(), $alias);
|
||||
chdir($cwd);
|
||||
}
|
||||
}
|
||||
|
||||
16
phpunit
Executable file
16
phpunit
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
if (isset($argv[1]) && $argv[1] === '--build-all') {
|
||||
unset($argv[1]);
|
||||
|
||||
$argv = array_values($argv);
|
||||
$argc = count($argv);
|
||||
|
||||
$_SERVER['argv'] = $argv;
|
||||
$_SERVER['argc'] = count($argv);
|
||||
|
||||
require_once __DIR__.'/tests/BuildAllBootstrap.php';
|
||||
}
|
||||
|
||||
require_once 'vendor/bin/phpunit';
|
||||
43
source/events.html
Normal file
43
source/events.html
Normal file
@@ -0,0 +1,43 @@
|
||||
{% block title %}Doctrine Events{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Events</h1>
|
||||
|
||||
{% if upcomingEvents|length %}
|
||||
<ul class="list-group">
|
||||
{% for event in upcomingEvents %}
|
||||
<div class="list-group mb-4">
|
||||
<a href="{{ path('event', {id:event.id, slug:event.slug}) }}" class="list-group-item list-group-item-action flex-column align-items-start">
|
||||
<h5 class="mb-1">{{ event.name }}</h5>
|
||||
|
||||
<p class="mb-1">
|
||||
This {{ event.dates.over ? 'was' : 'is' }} a {{ event.dates.duration }} event that {{ event.dates.over ? 'started' : 'starts' }} on {{ event.startDate|date('l, F jS Y') }} at {{ event.startDate|date('h:i A T') }}{% if event.dates.numDays > 1 %} and ends on {{ event.endDate|date('l, F jS Y') }} at {{ event.endDate|date('h:i A T') }}{% endif %}.
|
||||
</p>
|
||||
|
||||
<p class="mb-1">
|
||||
{% for speaker in event.speakers|slice(0, 5) %}
|
||||
<img src="{{ speaker.avatarUrl }}" title="{{ speaker.name }}" alt="{{ speaker.name }}" width="50" />
|
||||
{% endfor %}
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<p class="lead">Don't see something that you are interested in? <a href="{{ path('event_suggest') }}">Suggest</a> an event topic you would like to see and we will see what we can do!</p>
|
||||
{% else %}
|
||||
<p class="lead">No upcoming events are currently scheduled. Come back soon to check for new events! You may also <a href="{{ path('event_suggest') }}">suggest</a> an event topic you would like to see.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if pastEvents|length %}
|
||||
<h2>Past Events</h2>
|
||||
|
||||
<ul class="list-group">
|
||||
{% for event in pastEvents %}
|
||||
<li class="list-group-item"><a href="{{ path('event', {id:event.id, slug:event.slug}) }}">{{ event.name }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% include "carbonad-standard.html.twig" %}
|
||||
{% endblock %}
|
||||
12
source/events/suggest.html
Normal file
12
source/events/suggest.html
Normal file
@@ -0,0 +1,12 @@
|
||||
{% block title %}Suggest a Doctrine Event{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ path('events') }}">Events</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Suggest an Event</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<iframe src="https://docs.google.com/forms/d/e/1FAIpQLSeDhyTE57K50Ob-VwqyE9RZO8OCe56HLDd385NPltH4k4nY0g/viewform?embedded=true" width="640" height="667" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>
|
||||
{% endblock %}
|
||||
59
source/js/event.js
Normal file
59
source/js/event.js
Normal file
@@ -0,0 +1,59 @@
|
||||
export default function() {
|
||||
function openEventModal(label, message) {
|
||||
$('#event-modal-label').html(label);
|
||||
$('#event-modal-body').html(message);
|
||||
|
||||
$('#event-modal').modal();
|
||||
}
|
||||
|
||||
if (window.location.hash === '#success') {
|
||||
openEventModal(
|
||||
'Purchase Successful',
|
||||
'Your ticket purchase for <strong>' + window.event.name + '</strong> was successful! You will be e-mailed a receipt for your purchase immediately and details for joining the event will e-mailed 1 week before the event is scheduled to start.'
|
||||
);
|
||||
|
||||
window.location.hash = '';
|
||||
}
|
||||
|
||||
if (window.location.hash === '#canceled') {
|
||||
openEventModal(
|
||||
'Purchase Failure',
|
||||
'Oh no! Your ticket purchase for <strong>' + window.event.name + '</strong> was not successful. Please give it another try.'
|
||||
);
|
||||
|
||||
window.location.hash = '';
|
||||
}
|
||||
|
||||
if (window.location.hash === '#thanks') {
|
||||
openEventModal(
|
||||
'Event Finished',
|
||||
'Thanks for attending <strong>' + window.event.name + '</strong>! Keep your eyes open for more events in the future.'
|
||||
);
|
||||
|
||||
window.location.hash = '';
|
||||
}
|
||||
|
||||
$('#checkout-button').on('click', function() {
|
||||
$(this).addClass('disabled');
|
||||
});
|
||||
|
||||
$.getScript('https://js.stripe.com/v3', () => {
|
||||
var stripe = Stripe(window.stripePublishableKey);
|
||||
|
||||
var checkoutButton = document.getElementById('checkout-button');
|
||||
|
||||
checkoutButton.addEventListener('click', function () {
|
||||
stripe.redirectToCheckout({
|
||||
items: [{sku: window.event.sku, quantity: 1}],
|
||||
successUrl: window.event.url + '#success',
|
||||
cancelUrl: window.event.url + '#canceled',
|
||||
})
|
||||
.then(function (result) {
|
||||
if (result.error) {
|
||||
var displayError = document.getElementById('stripe-error-message');
|
||||
displayError.textContent = result.error.message;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
@@ -20,6 +20,12 @@ if ($('#sidebar').length > 0) {
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof window.event === 'object') {
|
||||
import(/* webpackChunkName: "event" */ './event').then(module => {
|
||||
module.default();
|
||||
});
|
||||
}
|
||||
|
||||
window.googleTranslateElementInit = () => {
|
||||
$('#google_translate_element').html('');
|
||||
|
||||
@@ -33,4 +39,5 @@ window.googleTranslateElementInit = () => {
|
||||
googleAnalyticsEvent('Translate', 'click', language);
|
||||
});
|
||||
};
|
||||
$.getScript('https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit');
|
||||
|
||||
$.getScript('https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit');
|
||||
|
||||
@@ -464,6 +464,10 @@ div.jsactive pre {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.modal-backdrop.in {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sidebar {
|
||||
display: none;
|
||||
|
||||
286
templates/emails/css/framework.css
Normal file
286
templates/emails/css/framework.css
Normal file
@@ -0,0 +1,286 @@
|
||||
/* -------------------------------------
|
||||
GLOBAL RESETS
|
||||
------------------------------------- */
|
||||
|
||||
/*All the styling goes here*/
|
||||
|
||||
img {
|
||||
border: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
max-width: 100%;
|
||||
}
|
||||
body {
|
||||
background-color: #f6f6f6;
|
||||
font-family: sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
table {
|
||||
border-collapse: separate;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
width: 100%; }
|
||||
table td {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
vertical-align: top;
|
||||
}
|
||||
/* -------------------------------------
|
||||
BODY & CONTAINER
|
||||
------------------------------------- */
|
||||
.body {
|
||||
background-color: #f6f6f6;
|
||||
width: 100%;
|
||||
}
|
||||
/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
|
||||
.container {
|
||||
display: block;
|
||||
margin: 0 auto !important;
|
||||
/* makes it centered */
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
width: 580px;
|
||||
}
|
||||
/* This should also be a block element, so that it will fill 100% of the .container */
|
||||
.content {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
max-width: 580px;
|
||||
padding: 10px;
|
||||
}
|
||||
/* -------------------------------------
|
||||
HEADER, FOOTER, MAIN
|
||||
------------------------------------- */
|
||||
.main {
|
||||
background: #ffffff;
|
||||
border-radius: 3px;
|
||||
width: 100%;
|
||||
}
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
}
|
||||
.content-block {
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.footer {
|
||||
clear: both;
|
||||
margin-top: 10px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
.footer td,
|
||||
.footer p,
|
||||
.footer span,
|
||||
.footer a {
|
||||
color: #999999;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
/* -------------------------------------
|
||||
TYPOGRAPHY
|
||||
------------------------------------- */
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4 {
|
||||
color: #000000;
|
||||
font-family: sans-serif;
|
||||
font-weight: 400;
|
||||
line-height: 1.4;
|
||||
margin: 0;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 35px;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
p,
|
||||
ul,
|
||||
ol {
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
p li,
|
||||
ul li,
|
||||
ol li {
|
||||
list-style-position: inside;
|
||||
margin-left: 5px;
|
||||
}
|
||||
a {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* -------------------------------------
|
||||
BUTTONS
|
||||
------------------------------------- */
|
||||
.btn {
|
||||
box-sizing: border-box;
|
||||
width: 100%; }
|
||||
.btn > tbody > tr > td {
|
||||
padding-bottom: 15px; }
|
||||
.btn table {
|
||||
width: auto;
|
||||
}
|
||||
.btn table td {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.btn a {
|
||||
background-color: #ffffff;
|
||||
border: solid 1px #3498db;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
color: #3498db;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding: 12px 25px;
|
||||
text-decoration: none;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
.btn-primary table td {
|
||||
background-color: #3498db;
|
||||
}
|
||||
.btn-primary a {
|
||||
background-color: #3498db;
|
||||
border-color: #3498db;
|
||||
color: #ffffff;
|
||||
}
|
||||
/* -------------------------------------
|
||||
OTHER STYLES THAT MIGHT BE USEFUL
|
||||
------------------------------------- */
|
||||
.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.first {
|
||||
margin-top: 0;
|
||||
}
|
||||
.align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.align-left {
|
||||
text-align: left;
|
||||
}
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
.mt0 {
|
||||
margin-top: 0;
|
||||
}
|
||||
.mb0 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.preheader {
|
||||
color: transparent;
|
||||
display: none;
|
||||
height: 0;
|
||||
max-height: 0;
|
||||
max-width: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
mso-hide: all;
|
||||
visibility: hidden;
|
||||
width: 0;
|
||||
}
|
||||
.powered-by a {
|
||||
text-decoration: none;
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
border-bottom: 1px solid #f6f6f6;
|
||||
margin: 20px 0;
|
||||
}
|
||||
/* -------------------------------------
|
||||
RESPONSIVE AND MOBILE FRIENDLY STYLES
|
||||
------------------------------------- */
|
||||
@media only screen and (max-width: 620px) {
|
||||
table[class=body] h1 {
|
||||
font-size: 28px !important;
|
||||
margin-bottom: 10px !important;
|
||||
}
|
||||
table[class=body] p,
|
||||
table[class=body] ul,
|
||||
table[class=body] ol,
|
||||
table[class=body] td,
|
||||
table[class=body] span,
|
||||
table[class=body] a {
|
||||
font-size: 16px !important;
|
||||
}
|
||||
table[class=body] .wrapper,
|
||||
table[class=body] .article {
|
||||
padding: 10px !important;
|
||||
}
|
||||
table[class=body] .content {
|
||||
padding: 0 !important;
|
||||
}
|
||||
table[class=body] .container {
|
||||
padding: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .main {
|
||||
border-left-width: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border-right-width: 0 !important;
|
||||
}
|
||||
table[class=body] .btn table {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .btn a {
|
||||
width: 100% !important;
|
||||
}
|
||||
table[class=body] .img-responsive {
|
||||
height: auto !important;
|
||||
max-width: 100% !important;
|
||||
width: auto !important;
|
||||
}
|
||||
}
|
||||
/* -------------------------------------
|
||||
PRESERVE THESE STYLES IN THE HEAD
|
||||
------------------------------------- */
|
||||
@media all {
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
.ExternalClass,
|
||||
.ExternalClass p,
|
||||
.ExternalClass span,
|
||||
.ExternalClass font,
|
||||
.ExternalClass td,
|
||||
.ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
.apple-link a {
|
||||
color: inherit !important;
|
||||
font-family: inherit !important;
|
||||
font-size: inherit !important;
|
||||
font-weight: inherit !important;
|
||||
line-height: inherit !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.btn-primary table td:hover {
|
||||
background-color: #34495e !important;
|
||||
}
|
||||
.btn-primary a:hover {
|
||||
background-color: #34495e !important;
|
||||
border-color: #34495e !important;
|
||||
}
|
||||
}
|
||||
8
templates/emails/css/layout.css
Normal file
8
templates/emails/css/layout.css
Normal file
@@ -0,0 +1,8 @@
|
||||
.header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header img {
|
||||
height: 60px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
13
templates/emails/email.html.twig
Normal file
13
templates/emails/email.html.twig
Normal file
@@ -0,0 +1,13 @@
|
||||
{% block subject '' %}
|
||||
|
||||
{% block head_css '' %}
|
||||
|
||||
{% block inline_css '' %}
|
||||
|
||||
{% block full_body_text %}
|
||||
{% block body_text '' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block full_body_html %}
|
||||
{% block body_html '' %}
|
||||
{% endblock %}
|
||||
21
templates/emails/events/participant-ticket.html.twig
Normal file
21
templates/emails/events/participant-ticket.html.twig
Normal file
@@ -0,0 +1,21 @@
|
||||
{% extends 'emails/layout.html.twig' %}
|
||||
|
||||
{% block subject %}
|
||||
[Doctrine Event] {{ event.name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block body_html %}
|
||||
<p>Hi {{ participant.email }},</p>
|
||||
|
||||
<p>You are receiving this e-mail because you registered for the Doctrine Event named <strong>{{ event.name }}</strong>.</p>
|
||||
|
||||
{% if event.conference %}
|
||||
<p>This event is hosted at <strong>{{ event.location.name }}</strong> which is located at <a href="https://www.google.com/maps?q={{ event.location.address.string }}" target="_blank" >{{ event.location.address.string }}</a>.</p>
|
||||
{% else %}
|
||||
<p>You can join the event at the following url: <a href="{{ event.joinUrl }}">{{ event.joinUrl }}</a></p>
|
||||
{% endif %}
|
||||
|
||||
<p>If you need help, e-mail us at <a href="mailto:events@doctrine-project.org?subject={{ event.name }} Help">events@doctrine-project.org</a>.</p>
|
||||
|
||||
<p>Thanks, Doctrine Team!</p>
|
||||
{% endblock %}
|
||||
64
templates/emails/layout.html.twig
Normal file
64
templates/emails/layout.html.twig
Normal file
@@ -0,0 +1,64 @@
|
||||
{% extends 'emails/email.html.twig' %}
|
||||
|
||||
{% block inline_css %}
|
||||
{% include 'emails/css/framework.css' %}
|
||||
{% include 'emails/css/layout.css' %}
|
||||
{% endblock %}
|
||||
|
||||
{% block full_body_html %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<title>Doctrine</title>
|
||||
|
||||
<style type="text/css">
|
||||
{% block head_css '' %}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<span class="preheader">{% block preheader '' %}</span>
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0" class="body">
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td class="header">
|
||||
<a href="{{ url('homepage') }}"><img src="{{ get_asset_url('/images/favicon-196x196.png', site.assetsUrl) }}" /></a>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td class="container">
|
||||
<div class="content">
|
||||
<table role="presentation" class="main">
|
||||
<tr>
|
||||
<td class="wrapper">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td>
|
||||
{% block body_html '' %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="footer">
|
||||
<table role="presentation" border="0" cellpadding="0" cellspacing="0">
|
||||
<tr>
|
||||
<td class="content-block">
|
||||
<span class="apple-link"><a href="{{ url('homepage') }}">Doctrine Company, LLC</a></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
27
templates/event-cfp.html.twig
Normal file
27
templates/event-cfp.html.twig
Normal file
@@ -0,0 +1,27 @@
|
||||
{% block title %}{{ event.name }}{% endblock %}
|
||||
|
||||
{% block meta_description event.description %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ path('events') }}">Events</a></li>
|
||||
<li class="breadcrumb-item"><a href="{{ path('event', {id:event.id, slug:event.slug}) }}">{{ event.name }}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">Call For Papers</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if event.cfp.exists %}
|
||||
{% if event.cfp.dates.now %}
|
||||
<p class="lead">Call for Papers started on <strong>{{ event.cfp.dates.start|date('l, F jS Y') }}</strong> and ends on <strong>{{ event.cfp.dates.end|date('l, F jS Y') }}</strong>.</p>
|
||||
|
||||
<iframe src="{{ event.cfp.embeddedGoogleFormUrl }}" width="640" height="930" frameborder="0" marginheight="0" marginwidth="0">Loading...</iframe>
|
||||
{% elseif event.cfp.dates.upcoming %}
|
||||
<p class="lead">Call for Papers starts on <strong>{{ event.cfp.dates.start|date('l, F jS Y') }}</strong> and ends on <strong>{{ event.cfp.dates.end|date('l, F jS Y') }}</strong>.</p>
|
||||
{% else %}
|
||||
{% include "alert.html.twig" with {alertMessage:event.name ~' call for papers has ended!'} %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% include "alert.html.twig" with {alertMessage:event.name ~' does not have a call for papers!'} %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
173
templates/event.html.twig
Normal file
173
templates/event.html.twig
Normal file
@@ -0,0 +1,173 @@
|
||||
{% block title %}{{ event.name }}{% endblock %}
|
||||
|
||||
{% block meta_description event.description %}
|
||||
|
||||
{% block content %}
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{{ path('events') }}">Events</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page">{{ event.name }}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
{% if event.dates.over %}
|
||||
{% set alertMessage %}
|
||||
This event has ended. Watch for additional <a href="{{ path('events') }}">events</a> in the future.
|
||||
{% endset %}
|
||||
|
||||
{% include "alert.html.twig" with {alertMessage:alertMessage} %}
|
||||
{% endif %}
|
||||
|
||||
<p class="lead">{{ event.description }}</p>
|
||||
|
||||
<div class="card mb-4 box-shadow">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-sm-12">
|
||||
<h1 class="card-title pricing-card-title">
|
||||
{% if event.free %}
|
||||
FREE!
|
||||
{% else %}
|
||||
${{ event.price|number_format }}
|
||||
{% endif %}
|
||||
</h1>
|
||||
|
||||
<p class="card-text">This {{ event.dates.over ? 'was' : 'is' }} a {{ event.dates.duration }} event that {{ event.dates.over ? 'started' : 'starts' }} on {{ event.startDate|date('l, F jS Y') }} at {{ event.startDate|date('h:i A T') }}{% if event.dates.numDays > 1 %} and ends on {{ event.endDate|date('l, F jS Y') }} at {{ event.endDate|date('h:i A T') }}{% endif %}.</p>
|
||||
|
||||
{% if event.registrationDates.now %}
|
||||
{% if event.free %}
|
||||
{% if event.joinUrl %}
|
||||
<a href="{{ event.joinUrl }}" class="btn btn-primary" target="_blank" rel="noopener noreferrer">Join Event</a>
|
||||
{% else %}
|
||||
<small class="text-muted">A join URL does not exist yet for this event yet. Check back when it gets closer to {{ event.startDate|date('l, F jS Y') }}.</small>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
id="checkout-button"
|
||||
role="link"
|
||||
>
|
||||
Purchase Ticket
|
||||
</button>
|
||||
{% endif %}
|
||||
{% elseif event.registrationDates.over %}
|
||||
<small class="text-muted">Registration is over for this event.</small>
|
||||
{% else %}
|
||||
<small class="text-muted">Registration will open on {{ event.registrationDates.start|date('l, F jS Y') }}.</small>
|
||||
{% endif %}
|
||||
|
||||
{% if event.cfp.dates.now %}
|
||||
<a href="{{ path('event_cfp', {id:event.id, slug:event.slug}) }}" class="btn btn-primary">Submit a Talk</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="col-4 d-none d-lg-block">
|
||||
{% include "carbonad-standard.html.twig" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if event.speakers|length %}
|
||||
<div class="card-footer text-muted">
|
||||
{% for speaker in event.speakers %}
|
||||
<a href="{{ path('event', {id:event.id, slug:event.slug}) }}#{{ speaker.topicSlug }}" title="{{ speaker.name }}"><img src="{{ speaker.avatarUrl }}" width="50" alt="{{ speaker.name }}" /></a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if event.conference %}
|
||||
<h1>Location</h1>
|
||||
|
||||
<p class="lead">This event is hosted at <strong>{{ event.location.name }}</strong> which is located at <a href="https://www.google.com/maps?q={{ event.location.address.string }}" target="_blank" rel="noopener noreferrer">{{ event.location.address.string }}</a>.</p>
|
||||
|
||||
<div class="mapouter mb-4"><div class="gmap_canvas"><iframe width="400" height="300" id="gmap_canvas" src="https://www.google.com/maps?q={{ event.location.address.string }}&t=&z=13&ie=UTF8&iwloc=&output=embed" frameborder="0" scrolling="no" marginheight="0" marginwidth="0"></iframe><a href="https://www.crocothemes.net"></a></div><style>.mapouter{position:relative;text-align:right;height:300px;width:400px;}.gmap_canvas {overflow:hidden;background:none!important;height:300px;width:400px;}</style></div>
|
||||
{% endif %}
|
||||
|
||||
{% if event.sponsors|length %}
|
||||
<h2>Sponsors</h2>
|
||||
|
||||
<p class="lead">
|
||||
Thanks to our sponsors! This event would not be possible without their support. If you are interested in becoming a sponsor, please contact us at <a href="mailto:sponsorship@doctrine-project.org?subject={{ event.name }} Sponsorship">sponsorship@doctrine-project.org</a>
|
||||
</p>
|
||||
|
||||
<div class="card-deck mb-3">
|
||||
{% for sponsor in event.sponsors %}
|
||||
<div class="card mb-4 box-shadow">
|
||||
<a href="{{ sponsor.urlWithUtmParameters }}" target="_blank"><img class="card-img-top p-2" height="100" src="{{ sponsor.logo }}" alt="{{ sponsor.name }}"></a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if event.schedule|length %}
|
||||
<h2>Schedule</h2>
|
||||
|
||||
<table class="table table-striped">
|
||||
{% for slot in event.schedule %}
|
||||
<tr>
|
||||
<td><a href="{{ path('event', {id:event.id, slug:event.slug}) }}#{{ slot.speaker.topicSlug }}"><strong>{{ slot.speaker.topic }}</strong></a> <span class="text-muted"><small>{{ slot.speaker.name }}</small></span></td>
|
||||
<td>{{ slot.startDate|date('h:i A T') }}</td>
|
||||
<td>{{ slot.endDate|date('h:i A T') }}</td>
|
||||
<td>{% if slot.speaker.hasYouTubeVideo() %}<a href="{{ slot.speaker.youTubeUrl }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-youtube text-danger"></i>{% endif %}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% if event.speakers|length %}
|
||||
<h2>Speakers</h2>
|
||||
|
||||
{% for speaker in event.speakers %}
|
||||
<a name="{{ speaker.topicSlug }}">
|
||||
<div class="card mb-4">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-auto">
|
||||
<img src="{{ speaker.avatarUrl }}" width="200" class="img-fluid" alt="{{ speaker.name }}" />
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card-block p-4">
|
||||
<h4 class="card-title">
|
||||
{{ speaker.topic }}
|
||||
|
||||
{% if speaker.hasYouTubeVideo() %}
|
||||
<a href="{{ speaker.youTubeUrl }}" target="_blank" rel="noopener noreferrer"><i class="fab fa-youtube text-danger"></i></a>
|
||||
{% endif %}
|
||||
</h4>
|
||||
<h5 class="card-subtitle mb-2 text-muted">{{ speaker.name }}</h5>
|
||||
<p class="card-text">{{ speaker.description|nl2br }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div id="event-modal" class="modal fade bd-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="event-modal-label"></h4>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body" id="event-modal-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="stripe-error-message"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
{% if not event.free %}
|
||||
window.stripePublishableKey = '{{ get_stripe_publishable_key() }}';
|
||||
{% endif %}
|
||||
|
||||
window.event = {
|
||||
name: '{{ event.name }}',
|
||||
sku: '{{ event.sku }}',
|
||||
url: '{{ url('event', {id:event.id, slug:event.slug}) }}'
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -137,27 +137,26 @@
|
||||
<a class="dropdown-item" href="{{ path('contribute') }}">Contributor Workflow</a>
|
||||
<a class="dropdown-item" href="{{ path('contribute_maintainer') }}">Maintainer Workflow</a>
|
||||
<a class="dropdown-item" href="{{ path('contribute_website') }}">Contribute to Website</a>
|
||||
<a class="dropdown-item" href="{{ path('team_maintainers') }}">Maintainers</a>
|
||||
<a class="dropdown-item" href="{{ path('team_contributors') }}">Contributors</a>
|
||||
<a class="dropdown-item" href="{{ path('policies') }}">Policies</a>
|
||||
<a class="dropdown-item" href="https://github.com/doctrine" target="_blank" rel="noopener noreferrer">GitHub</a>
|
||||
<a class="dropdown-item" href="{{ path('styleguide') }}">Styleguide</a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="nav-item{% if menuSlug == 'blog' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('blog') }}">Blog</a>
|
||||
<li class="nav-item{% if menuSlug == 'events' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('events') }}">Events</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown{% if menuSlug == 'team' %} active{% endif %}">
|
||||
<a class="nav-link dropdown-toggle" href="{{ path('team_maintainers') }}" id="navbarTeamDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Team</a>
|
||||
|
||||
<div class="dropdown-menu" aria-labelledby="navbarTeamDropdown">
|
||||
<a class="dropdown-item" href="{{ path('team_maintainers') }}">Maintainers</a>
|
||||
<a class="dropdown-item" href="{{ path('team_contributors') }}">Contributors</a>
|
||||
</div>
|
||||
<li class="nav-item{% if menuSlug == 'consulting' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('consulting') }}">Consulting</a>
|
||||
</li>
|
||||
|
||||
<li class="nav-item{% if menuSlug == 'partners' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('partners') }}">Partners</a>
|
||||
</li>
|
||||
<li class="nav-item{% if menuSlug == 'consulting' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('consulting') }}">Consulting</a>
|
||||
<li class="nav-item{% if menuSlug == 'blog' %} active{% endif %}">
|
||||
<a class="nav-link" href="{{ path('blog') }}">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -211,6 +210,7 @@
|
||||
<li class="list-inline-item"><a href="{{ path('sponsorship') }}">Sponsorship</a></li>
|
||||
<li class="list-inline-item"><a href="{{ path('community') }}">Community</a></li>
|
||||
<li class="list-inline-item"><a href="{{ path('blog') }}">Blog</a></li>
|
||||
<li class="list-inline-item"><a href="{{ path('events') }}">Events</a></li>
|
||||
<li class="list-inline-item"><a href="{{ path('consulting') }}">Consulting</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Tests\Assets;
|
||||
|
||||
use Doctrine\Website\Assets\AssetIntegrityGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
|
||||
class AssetIntegrityGeneratorTest extends TestCase
|
||||
{
|
||||
|
||||
40
tests/BuildAllBootstrap.php
Normal file
40
tests/BuildAllBootstrap.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Tests;
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Doctrine\Website\Application;
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use function strpos;
|
||||
|
||||
final class BuildAllBootstrap
|
||||
{
|
||||
private const COMMAND = 'build-all';
|
||||
|
||||
public function __invoke() : void
|
||||
{
|
||||
$container = Application::getContainer('test');
|
||||
|
||||
/** @var Application $application */
|
||||
$application = $container->get(Application::class);
|
||||
|
||||
$consoleApplication = $application->getConsoleApplication();
|
||||
$consoleApplication->setAutoExit(false);
|
||||
|
||||
$input = new ArrayInput([
|
||||
'command' => self::COMMAND,
|
||||
]);
|
||||
|
||||
$consoleApplication->find(self::COMMAND)
|
||||
->run($input, new ConsoleOutput());
|
||||
}
|
||||
}
|
||||
|
||||
// only execute this for phpunit
|
||||
if (strpos($_SERVER['PHP_SELF'], 'phpunit') !== false) {
|
||||
(new BuildAllBootstrap())->__invoke();
|
||||
}
|
||||
@@ -5,8 +5,8 @@ declare(strict_types=1);
|
||||
namespace Doctrine\Website\Tests\Cache;
|
||||
|
||||
use Doctrine\Website\Cache\CacheClearer;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
|
||||
class CacheClearerTest extends TestCase
|
||||
|
||||
@@ -10,8 +10,8 @@ use Doctrine\StaticWebsiteGenerator\SourceFile\SourceFileFilesystemReader;
|
||||
use Doctrine\StaticWebsiteGenerator\SourceFile\SourceFileParameters;
|
||||
use Doctrine\StaticWebsiteGenerator\SourceFile\SourceFiles;
|
||||
use Doctrine\Website\DataBuilder\BlogPostDataBuilder;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use function usort;
|
||||
|
||||
class BlogPostDataBuilderTest extends TestCase
|
||||
|
||||
@@ -6,12 +6,10 @@ namespace Doctrine\Website\Tests\DataBuilder;
|
||||
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use Doctrine\Website\DataBuilder\ContributorDataBuilder;
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\ProjectContributor;
|
||||
use Doctrine\Website\Model\TeamMember;
|
||||
use Doctrine\Website\Repositories\ProjectContributorRepository;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ContributorDataBuilderTest extends TestCase
|
||||
{
|
||||
@@ -23,16 +21,15 @@ class ContributorDataBuilderTest extends TestCase
|
||||
|
||||
public function testBuild() : void
|
||||
{
|
||||
$project1 = new Project(['slug' => 'dbal']);
|
||||
$project2 = new Project(['slug' => 'orm']);
|
||||
$project1 = $this->createProject(['slug' => 'dbal']);
|
||||
$project2 = $this->createProject(['slug' => 'orm']);
|
||||
|
||||
$jwageTeamMember = new TeamMember();
|
||||
$ocramiusTeamMember = new TeamMember();
|
||||
|
||||
$objectManager = $this->createMock(ObjectManagerInterface::class);
|
||||
|
||||
$projectContributor1 = new ProjectContributor();
|
||||
$projectContributor1->hydrate([
|
||||
$projectContributor1 = $this->createProjectContributor([
|
||||
'github' => 'jwage',
|
||||
'teamMember' => $jwageTeamMember,
|
||||
'avatarUrl' => 'https://avatars1.githubusercontent.com/u/97422?s=460&v=4',
|
||||
@@ -40,10 +37,9 @@ class ContributorDataBuilderTest extends TestCase
|
||||
'numAdditions' => 1,
|
||||
'numDeletions' => 1,
|
||||
'project' => $project1,
|
||||
], $objectManager);
|
||||
]);
|
||||
|
||||
$projectContributor2 = new ProjectContributor();
|
||||
$projectContributor2->hydrate([
|
||||
$projectContributor2 = $this->createProjectContributor([
|
||||
'github' => 'jwage',
|
||||
'teamMember' => $jwageTeamMember,
|
||||
'avatarUrl' => 'https://avatars1.githubusercontent.com/u/97422?s=460&v=4',
|
||||
@@ -51,10 +47,9 @@ class ContributorDataBuilderTest extends TestCase
|
||||
'numAdditions' => 1,
|
||||
'numDeletions' => 1,
|
||||
'project' => $project2,
|
||||
], $objectManager);
|
||||
]);
|
||||
|
||||
$projectContributor3 = new ProjectContributor();
|
||||
$projectContributor3->hydrate([
|
||||
$projectContributor3 = $this->createProjectContributor([
|
||||
'github' => 'ocramius',
|
||||
'teamMember' => $ocramiusTeamMember,
|
||||
'avatarUrl' => 'https://avatars0.githubusercontent.com/u/154256?s=460&v=4',
|
||||
@@ -62,7 +57,7 @@ class ContributorDataBuilderTest extends TestCase
|
||||
'numAdditions' => 1,
|
||||
'numDeletions' => 1,
|
||||
'project' => $project2,
|
||||
], $objectManager);
|
||||
]);
|
||||
|
||||
$projectContributors = [$projectContributor1, $projectContributor2, $projectContributor3];
|
||||
|
||||
|
||||
@@ -4,15 +4,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Tests\DataBuilder;
|
||||
|
||||
use Doctrine\SkeletonMapper\ObjectManagerInterface;
|
||||
use Doctrine\Website\DataBuilder\ProjectContributorDataBuilder;
|
||||
use Doctrine\Website\Github\GithubProjectContributors;
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\TeamMember;
|
||||
use Doctrine\Website\Repositories\ProjectRepository;
|
||||
use Doctrine\Website\Repositories\TeamMemberRepository;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ProjectContributorDataBuilderTest extends TestCase
|
||||
{
|
||||
@@ -30,10 +28,8 @@ class ProjectContributorDataBuilderTest extends TestCase
|
||||
|
||||
public function testBuild() : void
|
||||
{
|
||||
$objectManager = $this->createMock(ObjectManagerInterface::class);
|
||||
|
||||
$project1 = new Project(['slug' => 'orm']);
|
||||
$project2 = new Project(['slug' => 'dbal']);
|
||||
$project1 = $this->createProject(['slug' => 'orm']);
|
||||
$project2 = $this->createProject(['slug' => 'dbal']);
|
||||
|
||||
$jwageTeamMember = $this->createMock(TeamMember::class);
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ use Doctrine\Website\Projects\ProjectDataReader;
|
||||
use Doctrine\Website\Projects\ProjectDataRepository;
|
||||
use Doctrine\Website\Projects\ProjectGitSyncer;
|
||||
use Doctrine\Website\Projects\ProjectVersionsReader;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ProjectDataBuilderTest extends TestCase
|
||||
{
|
||||
|
||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Tests\DataSources;
|
||||
|
||||
use Doctrine\Website\DataSources\DoctrineUsers;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Doctrine\Website\DataSources\ArrayDataSource;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
|
||||
class DoctrineUsersTest extends TestCase
|
||||
class ArrayDataSourceTest extends TestCase
|
||||
{
|
||||
public function testGetSourceRows() : void
|
||||
{
|
||||
@@ -22,8 +22,8 @@ class DoctrineUsersTest extends TestCase
|
||||
],
|
||||
];
|
||||
|
||||
$doctrineUsers = new DoctrineUsers($rows);
|
||||
$dataSource = new ArrayDataSource($rows);
|
||||
|
||||
self::assertEquals($rows, $doctrineUsers->getSourceRows());
|
||||
self::assertEquals($rows, $dataSource->getSourceRows());
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,8 @@ use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\TeamMember;
|
||||
use Doctrine\Website\Repositories\ProjectRepository;
|
||||
use Doctrine\Website\Repositories\TeamMemberRepository;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ContributorsTest extends TestCase
|
||||
{
|
||||
|
||||
@@ -12,8 +12,8 @@ use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\TeamMember;
|
||||
use Doctrine\Website\Repositories\ProjectRepository;
|
||||
use Doctrine\Website\Repositories\TeamMemberRepository;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class ProjectContributorsTest extends TestCase
|
||||
{
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Website\Tests\DataSources;
|
||||
|
||||
use Doctrine\Website\DataSources\TeamMembers;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
|
||||
class TeamMembersTest extends TestCase
|
||||
{
|
||||
/** @var TeamMembers */
|
||||
private $teamMembers;
|
||||
|
||||
protected function setUp() : void
|
||||
{
|
||||
$this->teamMembers = new TeamMembers([
|
||||
['name' => 'ocramius'],
|
||||
['name' => 'jwage'],
|
||||
['name' => 'romanb'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function testGetSourceRows() : void
|
||||
{
|
||||
$teamMemberRows = $this->teamMembers->getSourceRows();
|
||||
|
||||
self::assertSame([
|
||||
['name' => 'ocramius'],
|
||||
['name' => 'jwage'],
|
||||
['name' => 'romanb'],
|
||||
], $teamMemberRows);
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ class DeployerTest extends TestCase
|
||||
|
||||
$this->processFactory->expects(self::at(2))
|
||||
->method('run')
|
||||
->with('cd /data/doctrine-website-staging && ./bin/console sync-repositories && ./bin/console build-website-data && ./bin/console build-docs && ./bin/console build-website /data/doctrine-website-build-staging --env=staging --publish')
|
||||
->with('cd /data/doctrine-website-staging && ./bin/console migrations:migrate --no-interaction --env=staging && ./bin/console build-all /data/doctrine-website-build-staging --env=staging --publish')
|
||||
->willReturn($process);
|
||||
|
||||
$deployer->deploy($output);
|
||||
|
||||
@@ -12,7 +12,6 @@ use Doctrine\Website\Docs\RST\RSTCopier;
|
||||
use Doctrine\Website\Docs\RST\RSTFileRepository;
|
||||
use Doctrine\Website\Docs\RST\RSTLanguage;
|
||||
use Doctrine\Website\Docs\RST\RSTPostBuildProcessor;
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\ProjectVersion;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
@@ -67,7 +66,7 @@ class RSTBuilderTest extends TestCase
|
||||
|
||||
public function testBuildRSTDocs() : void
|
||||
{
|
||||
$project = new Project([
|
||||
$project = $this->createProject([
|
||||
'slug' => 'project-slug',
|
||||
'docsSlug' => 'docs-slug',
|
||||
]);
|
||||
|
||||
@@ -11,7 +11,6 @@ use Doctrine\RST\Configuration;
|
||||
use Doctrine\RST\Environment;
|
||||
use Doctrine\RST\Kernel;
|
||||
use Doctrine\Website\Docs\SearchIndexer;
|
||||
use Doctrine\Website\Model\Project;
|
||||
use Doctrine\Website\Model\ProjectVersion;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
@@ -66,7 +65,7 @@ class SearchIndexerTest extends TestCase
|
||||
|
||||
public function testBuildSearchIndexes() : void
|
||||
{
|
||||
$project = new Project([
|
||||
$project = $this->createProject([
|
||||
'shortName' => 'ORM',
|
||||
'docsSlug' => 'doctrine-orm',
|
||||
'slug' => 'orm',
|
||||
|
||||
@@ -8,8 +8,8 @@ use DateTimeImmutable;
|
||||
use Doctrine\Website\Git\Tag;
|
||||
use Doctrine\Website\Git\TagBranchGuesser;
|
||||
use Doctrine\Website\ProcessFactory;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class TagBranchGuesserTest extends TestCase
|
||||
|
||||
@@ -6,8 +6,8 @@ namespace Doctrine\Website\Tests\Git;
|
||||
|
||||
use Doctrine\Website\Git\TagReader;
|
||||
use Doctrine\Website\ProcessFactory;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class TagReaderTest extends TestCase
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Doctrine\Website\Tests\Git;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Website\Git\Tag;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Doctrine\Website\Tests\TestCase;
|
||||
|
||||
class TagTest extends TestCase
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user