├── translations
├── .gitignore
├── validators+intl-icu.zh-hans.yaml
├── validators+intl-icu.ja.yaml
├── validators+intl-icu.en.yaml
├── messages+intl-icu.zh-hans.yaml
├── messages+intl-icu.ja.yaml
└── messages+intl-icu.en.yaml
├── src
├── Controller
│ ├── .gitignore
│ ├── StaffController.php
│ └── FragmentsController.php
├── Query
│ ├── CraftCMS
│ │ ├── graphql
│ │ │ ├── feeds
│ │ │ │ ├── comments.graphql
│ │ │ │ ├── events.graphql
│ │ │ │ ├── news.graphql
│ │ │ │ ├── press-releases.graphql
│ │ │ │ └── blog.graphql
│ │ │ ├── fragments
│ │ │ │ ├── contentImage.graphql
│ │ │ │ ├── thumbnailImage.graphql
│ │ │ │ ├── breadcrumbs.graphql
│ │ │ │ ├── listingEvent.graphql
│ │ │ │ ├── listingExternalEvent.graphql
│ │ │ │ ├── listingPageEvent.graphql
│ │ │ │ ├── defaultFlexibleComponents.graphql
│ │ │ │ ├── ecosystemsBottomFlexibleComponents.graphql
│ │ │ │ ├── ecosystemsFlexibleComponents.graphql
│ │ │ │ └── landingFlexibleComponents.graphql
│ │ │ ├── blog
│ │ │ │ ├── comment.graphql
│ │ │ │ ├── create-comment.graphql
│ │ │ │ ├── comments.graphql
│ │ │ │ ├── filters.graphql
│ │ │ │ ├── listing.graphql
│ │ │ │ ├── collection.graphql
│ │ │ │ └── entry.graphql
│ │ │ ├── taxonomies
│ │ │ │ ├── tags.graphql
│ │ │ │ ├── categories.graphql
│ │ │ │ ├── category-info.graphql
│ │ │ │ └── group-info.graphql
│ │ │ ├── newsletters
│ │ │ │ ├── entry.graphql
│ │ │ │ ├── filters.graphql
│ │ │ │ ├── collection.graphql
│ │ │ │ └── listing.graphql
│ │ │ ├── news
│ │ │ │ ├── filters.graphql
│ │ │ │ ├── listing.graphql
│ │ │ │ ├── collection.graphql
│ │ │ │ └── entry.graphql
│ │ │ ├── press-releases
│ │ │ │ ├── filters.graphql
│ │ │ │ ├── listing.graphql
│ │ │ │ ├── collection.graphql
│ │ │ │ └── entry.graphql
│ │ │ ├── events
│ │ │ │ ├── page.graphql
│ │ │ │ ├── listing.graphql
│ │ │ │ ├── filters.graphql
│ │ │ │ └── entry.graphql
│ │ │ ├── ecosystems
│ │ │ │ ├── testimonials.graphql
│ │ │ │ ├── ecosystem.graphql
│ │ │ │ └── recent-activities.graphql
│ │ │ ├── singles-breadcrumbs.graphql
│ │ │ ├── staff
│ │ │ │ └── alumni.graphql
│ │ │ ├── home
│ │ │ │ ├── recent-activities.graphql
│ │ │ │ └── page.graphql
│ │ │ ├── global-navigation.graphql
│ │ │ └── page.graphql
│ │ ├── Blog
│ │ │ ├── Comment.php
│ │ │ ├── Comments.php
│ │ │ ├── CreateComment.php
│ │ │ └── Listing.php
│ │ ├── Feeds
│ │ │ ├── Comments.php
│ │ │ ├── News.php
│ │ │ ├── PressReleases.php
│ │ │ ├── Blog.php
│ │ │ ├── Events.php
│ │ │ └── Taxonomy.php
│ │ ├── Taxonomies
│ │ │ ├── Tags.php
│ │ │ ├── Categories.php
│ │ │ ├── GroupInfo.php
│ │ │ └── CategoryInfo.php
│ │ ├── Newsletters
│ │ │ ├── Entry.php
│ │ │ ├── Listing.php
│ │ │ ├── Filters.php
│ │ │ └── Collection.php
│ │ ├── News
│ │ │ ├── Listing.php
│ │ │ └── Filters.php
│ │ ├── Events
│ │ │ └── Page.php
│ │ ├── PressReleases
│ │ │ ├── Listing.php
│ │ │ └── Filters.php
│ │ ├── Staff
│ │ │ └── AlumniListing.php
│ │ ├── Ecosystems
│ │ │ ├── Testimonials.php
│ │ │ └── Ecosystem.php
│ │ └── Home
│ │ │ └── RecentActivities.php
│ └── W3C
│ │ ├── Ecosystem
│ │ ├── Bizdev.php
│ │ ├── BizdevLead.php
│ │ ├── Members.php
│ │ ├── Groups.php
│ │ └── Evangelists.php
│ │ ├── Group.php
│ │ ├── Healthcheck.php
│ │ └── Home
│ │ └── Members.php
├── Service
│ ├── W3C.php
│ ├── CraftCMS.php
│ └── FeedHelper.php
├── Kernel.php
└── Form
│ └── CommentType.php
├── docs
├── front-end-integration
│ ├── testing.md
│ ├── README.md
│ ├── matrix-flexible-components.md
│ ├── routing.md
│ └── templating.md
├── images
│ ├── matrix-graphql.png
│ ├── matrix-craft-cms.png
│ ├── section-craft-cms.png
│ ├── content-field-craft-cms.png
│ ├── graphiql_execute_button.png
│ └── matrix-graphql-explorer.png
├── README.md
├── routing.md
├── git_workflow.md
├── continuous_integration.md
├── testing.md
├── configuration.md
├── internationalization.md
└── adding-languages.md
├── .env.dev
├── config
├── packages
│ ├── lock.yaml
│ ├── test
│ │ ├── twig.yaml
│ │ ├── validator.yaml
│ │ ├── framework.yaml
│ │ ├── web_profiler.yaml
│ │ └── monolog.yaml
│ ├── cache.yaml
│ ├── dev
│ │ ├── routing.yaml
│ │ ├── web_profiler.yaml
│ │ ├── debug.yaml
│ │ ├── framework.yaml
│ │ ├── assets.yaml
│ │ └── monolog.yaml
│ ├── mailer.yaml
│ ├── strata.yaml
│ ├── twig.yaml
│ ├── assets.yaml
│ ├── translation.yaml
│ ├── exercise_html_purifier.yaml
│ ├── validator.yaml
│ ├── prod
│ │ ├── deprecations.yaml
│ │ └── monolog.yaml
│ ├── routing.yaml
│ ├── nelmio_cors.yaml
│ ├── notifier.yaml
│ ├── fos_http_cache.yaml
│ ├── framework.yaml
│ ├── security.yaml
│ ├── nyholm_psr7.yaml
│ └── chrisguitarguy_request_id.yaml
├── routes
│ ├── dev
│ │ ├── framework.yaml
│ │ └── web_profiler.yaml
│ └── annotations.yaml
├── preload.php
├── routes.yaml
├── bundles.php
└── services.yaml
├── public
├── favicon.ico
└── index.php
├── .phplint.yml
├── w3c.json
├── .ddev
├── ddev-docker-compose-communicate.yaml
└── docker-compose.mounts.yaml
├── .env.prod
├── tests
├── symfony-container.php
├── bootstrap.php
├── urls
│ └── test-urls.php
└── Controller
│ └── DefaultControllerTest.php
├── .env.test
├── templates
├── staff
│ └── alumni.html.twig
├── news
│ ├── show.html.twig
│ └── index.html.twig
├── pages
│ ├── landing.html.twig
│ ├── default.html.twig
│ └── home.html.twig
├── events
│ ├── show.html.twig
│ └── index.html.twig
├── bundles
│ └── W3CWebsiteTemplatesBundle
│ │ ├── base.html.twig
│ │ └── components
│ │ └── styles
│ │ └── global_nav.html.twig
├── press-releases
│ ├── show.html.twig
│ └── index.html.twig
├── newsletters
│ └── index.html.twig
├── ecosystems
│ └── show.html.twig
├── blog
│ ├── index.html.twig
│ └── show.html.twig
├── rss_entry.html.twig
├── debug
│ └── test.html.twig
├── partials
│ ├── defaultFlexibleComponents.html.twig
│ ├── landingFlexibleComponents.html.twig
│ └── ecosystemsFlexibleComponents.html.twig
└── strata-logo.svg
├── bin
├── phpunit
└── console
├── phpcs.xml.dist
├── .env.local.dist
├── .gitignore
├── phpunit.xml.dist
├── rector.php
├── .github
└── workflows
│ └── php.yml
└── .env
/translations/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/Controller/.gitignore:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/front-end-integration/testing.md:
--------------------------------------------------------------------------------
1 | # Testing
2 |
3 | TODO
4 |
--------------------------------------------------------------------------------
/.env.dev:
--------------------------------------------------------------------------------
1 | ASSETS_WEBSITE_2021=https://www.w3.org/assets/website-2021/
2 |
--------------------------------------------------------------------------------
/config/packages/lock.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | lock: '%env(LOCK_DSN)%'
3 |
--------------------------------------------------------------------------------
/config/packages/test/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | strict_variables: true
3 |
--------------------------------------------------------------------------------
/config/packages/cache.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | cache:
3 | app: cache.adapter.filesystem
4 |
--------------------------------------------------------------------------------
/config/packages/dev/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | strict_requirements: null
--------------------------------------------------------------------------------
/config/packages/mailer.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | mailer:
3 | dsn: '%env(MAILER_DSN)%'
4 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/.phplint.yml:
--------------------------------------------------------------------------------
1 | path: ./
2 | jobs: 10
3 | extensions:
4 | - php
5 | exclude:
6 | - vendor
7 | - var
8 |
--------------------------------------------------------------------------------
/config/packages/test/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | not_compromised_password: false
4 |
--------------------------------------------------------------------------------
/docs/images/matrix-graphql.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/matrix-graphql.png
--------------------------------------------------------------------------------
/w3c.json:
--------------------------------------------------------------------------------
1 | {
2 | "group": [122803]
3 | , "contacts": ["vivienlacourba"]
4 | , "repo-type": "tool"
5 | }
6 |
--------------------------------------------------------------------------------
/docs/images/matrix-craft-cms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/matrix-craft-cms.png
--------------------------------------------------------------------------------
/docs/images/section-craft-cms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/section-craft-cms.png
--------------------------------------------------------------------------------
/config/packages/strata.yaml:
--------------------------------------------------------------------------------
1 | strata:
2 | tags:
3 | enabled: true
4 | preview_mode:
5 | data_provider: 'craft'
--------------------------------------------------------------------------------
/docs/images/content-field-craft-cms.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/content-field-craft-cms.png
--------------------------------------------------------------------------------
/docs/images/graphiql_execute_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/graphiql_execute_button.png
--------------------------------------------------------------------------------
/docs/images/matrix-graphql-explorer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3c/w3c-website-frontend/HEAD/docs/images/matrix-graphql-explorer.png
--------------------------------------------------------------------------------
/config/routes/dev/framework.yaml:
--------------------------------------------------------------------------------
1 | _errors:
2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml'
3 | prefix: /_error
4 |
--------------------------------------------------------------------------------
/.ddev/ddev-docker-compose-communicate.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | web:
3 | external_links:
4 | - "ddev-router:w3c-website-craft.ddev.site/api"
--------------------------------------------------------------------------------
/config/packages/test/framework.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | test: true
3 | session:
4 | storage_factory_id: session.storage.factory.mock_file
5 |
--------------------------------------------------------------------------------
/config/packages/twig.yaml:
--------------------------------------------------------------------------------
1 | twig:
2 | default_path: '%kernel.project_dir%/templates'
3 | globals:
4 | default_locale: '%env(APP_DEFAULT_LOCALE)%'
5 |
--------------------------------------------------------------------------------
/.ddev/docker-compose.mounts.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | web:
3 | volumes:
4 | - "~/Sites/w3c/w3c-website-templates-bundle:/home/w3c-website-templates-bundle"
5 |
--------------------------------------------------------------------------------
/config/packages/test/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: false
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler: { collect: false }
7 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/feeds/comments.graphql:
--------------------------------------------------------------------------------
1 | query comments($owners: [QueryArgument]) {
2 | comments(ownerId: $owners) {
3 | ownerId
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/Service/W3C.php:
--------------------------------------------------------------------------------
1 | boot();
9 |
10 | return $appKernel->getContainer();
11 |
--------------------------------------------------------------------------------
/config/packages/assets.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | assets:
3 | packages:
4 | website-2021:
5 | base_path: '%env(ASSETS_WEBSITE_2021)%'
6 | logos:
7 | base_path: '/assets/logos/'
8 |
--------------------------------------------------------------------------------
/config/packages/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler:
2 | toolbar: true
3 | intercept_redirects: false
4 |
5 | framework:
6 | profiler:
7 | only_exceptions: false
8 | collect: '%env(bool:ENABLE_DEV_PROFILER)%'
9 |
--------------------------------------------------------------------------------
/.env.test:
--------------------------------------------------------------------------------
1 | # define your env variables for the test env here
2 | KERNEL_CLASS='App\Kernel'
3 | APP_SECRET='$ecretf0rt3st'
4 | SYMFONY_DEPRECATIONS_HELPER=999999
5 | PANTHER_APP_ENV=panther
6 | PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
7 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/taxonomies/categories.graphql:
--------------------------------------------------------------------------------
1 | query Categories($site: [String], $handle: [String]) {
2 | categories(site: $site, group: $handle) {
3 | id
4 | title
5 | uri
6 | slug
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/config/packages/translation.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | default_locale: '%env(APP_DEFAULT_LOCALE)%'
3 | translator:
4 | default_path: '%kernel.project_dir%/translations'
5 | fallbacks:
6 | - '%env(APP_DEFAULT_LOCALE)%'
7 |
--------------------------------------------------------------------------------
/config/routes.yaml:
--------------------------------------------------------------------------------
1 | controllers:
2 | resource:
3 | path: ../src/Controller/
4 | namespace: App\Controller
5 | type: attribute
6 |
7 | ekreative_health_check:
8 | resource: '@EkreativeHealthCheckBundle/Resources/config/routes.xml'
9 |
--------------------------------------------------------------------------------
/config/packages/dev/debug.yaml:
--------------------------------------------------------------------------------
1 | debug:
2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser.
3 | # See the "server:dump" command to start a new server.
4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%"
5 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/taxonomies/category-info.graphql:
--------------------------------------------------------------------------------
1 | query CategoryInfo($site: [String], $handle: [String], $slug: [String]) {
2 | category(site: $site, group: $handle, slug: $slug) {
3 | id
4 | title
5 | uri
6 | slug
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/config/routes/dev/web_profiler.yaml:
--------------------------------------------------------------------------------
1 | web_profiler_wdt:
2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml'
3 | prefix: /_wdt
4 |
5 | web_profiler_profiler:
6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml'
7 | prefix: /_profiler
8 |
--------------------------------------------------------------------------------
/templates/staff/alumni.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/listing.html.twig' %}
2 |
3 | {% block list %}
4 | {% include '@W3CWebsiteTemplates/components/styles/alumni.html.twig' with { 'alumni': alumni } %}
5 | {% endblock %}
6 |
7 | {% block pagination %}{% endblock %}
8 |
--------------------------------------------------------------------------------
/config/packages/dev/framework.yaml:
--------------------------------------------------------------------------------
1 | # see https://symfony.com/doc/current/reference/configuration/framework.html
2 | framework:
3 | http_client:
4 | default_options:
5 | # Disable SSL verification on local dev only
6 | verify_host: false
7 | verify_peer: false
--------------------------------------------------------------------------------
/templates/news/show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/post.html.twig' %}
2 |
3 | {% set body_classes = 'post' %}
4 |
5 | {% block feed %}
6 | {% include '@W3CWebsiteTemplates/components/styles/feed.html.twig' with { 'feed_url': '/news/feed', 'feed_type': 'news' } %}
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/templates/pages/landing.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/landing.html.twig' %}
2 |
3 | {% block components %}
4 | {% for component in page.landingFlexibleComponents %}
5 | {{ include('partials/landingFlexibleComponents.html.twig') }}
6 | {% endfor %}
7 | {% endblock %}
8 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/newsletters/entry.graphql:
--------------------------------------------------------------------------------
1 | query NewsletterEntry($date: [String], $site: [String]) {
2 | entry(postDate: $date, site: $site, section: "newsletter") {
3 | title
4 | ... on newsletter_default_Entry {
5 | fullDocumentContent
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/config/packages/exercise_html_purifier.yaml:
--------------------------------------------------------------------------------
1 | exercise_html_purifier:
2 | # full configuration reference: http://htmlpurifier.org/live/configdoc/plain.html
3 | html_profiles:
4 | custom:
5 | config:
6 | Core.Encoding: 'UTF-8'
7 | AutoFormat.AutoParagraph: true
8 |
--------------------------------------------------------------------------------
/config/packages/validator.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | validation:
3 | email_validation_mode: html5
4 |
5 | # Enables validator auto-mapping support.
6 | # For instance, basic validation constraints will be inferred from Doctrine's metadata.
7 | #auto_mapping:
8 | # App\Entity\: []
9 |
--------------------------------------------------------------------------------
/config/packages/dev/assets.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | assets:
3 | packages:
4 | website-2021:
5 | base_urls: '%env(ASSETS_WEBSITE_2021)%'
6 | base_path: ~
7 | logos:
8 | base_urls: 'https://www.w3.org/assets/logos/'
9 | base_path: ~
10 |
--------------------------------------------------------------------------------
/config/packages/prod/deprecations.yaml:
--------------------------------------------------------------------------------
1 | # As of Symfony 5.1, deprecations are logged in the dedicated "deprecation" channel when it exists
2 | #monolog:
3 | # channels: [deprecation]
4 | # handlers:
5 | # deprecation:
6 | # type: stream
7 | # channels: [deprecation]
8 | # path: php://stderr
9 |
--------------------------------------------------------------------------------
/templates/events/show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/event.html.twig' %}
2 |
3 | {% set body_classes = 'event' %}
4 |
5 | {% block components %}
6 | {% for component in page.defaultFlexibleComponents %}
7 | {{ include('partials/defaultFlexibleComponents.html.twig') }}
8 | {% endfor %}
9 | {% endblock %}
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/taxonomies/group-info.graphql:
--------------------------------------------------------------------------------
1 | query GroupInfo($site: [String], $slug: [String]) {
2 | category(site: $site, group: "groups", slug: $slug) {
3 | id
4 | title
5 | uri
6 | slug
7 | ... on groups_Category {
8 | type: groupType
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.zh-hans.yaml:
--------------------------------------------------------------------------------
1 | blog:
2 | comments:
3 | form:
4 | name:
5 | blank: 请输入姓名
6 | email:
7 | blank: 请输入电子邮箱地址
8 | format: 请输入有效的电子邮箱地址
9 | comment:
10 | blank: 请输入评论
11 | post:
12 | blank: 评论必须提及某一博客链接
13 |
--------------------------------------------------------------------------------
/config/packages/routing.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | router:
3 | # Configure how to generate URLs in non-HTTP contexts, such as CLI commands.
4 | # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands
5 | default_uri: '%env(APP_URL)%'
6 |
7 | when@prod:
8 | framework:
9 | router:
10 | strict_requirements: null
11 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/news/filters.graphql:
--------------------------------------------------------------------------------
1 | query NewsFilters($site: [String]) {
2 | first: entry(section: "newsArticles", site: $site, orderBy: "postDate asc") {
3 | year: postDate@formatDateTime(format: "Y")
4 | }
5 | last: entry(section: "newsArticles", site: $site, orderBy: "postDate desc") {
6 | year: postDate@formatDateTime(format: "Y")
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__) . '/.env');
11 | }
12 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/newsletters/filters.graphql:
--------------------------------------------------------------------------------
1 | query NewsletterFilters($site: [String]) {
2 | first: entry(section: "newsletter", site: $site, orderBy: "postDate asc") {
3 | year: postDate@formatDateTime(format: "Y")
4 | }
5 | last: entry(section: "newsletter", site: $site, orderBy: "postDate desc") {
6 | year: postDate@formatDateTime(format: "Y")
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/press-releases/filters.graphql:
--------------------------------------------------------------------------------
1 | query PressReleasesFilters($site: [String]) {
2 | first: entry(section: "pressReleases", site: $site, orderBy: "postDate asc") {
3 | year: postDate@formatDateTime(format: "Y")
4 | }
5 | last: entry(section: "pressReleases", site: $site, orderBy: "postDate desc") {
6 | year: postDate@formatDateTime(format: "Y")
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.ja.yaml:
--------------------------------------------------------------------------------
1 | blog:
2 | comments:
3 | form:
4 | name:
5 | blank: 名前を入力してください
6 | email:
7 | blank: メールアドレスを入力してください
8 | format: 有効なメールアドレスを入力してください
9 | comment:
10 | blank: コメントを入力してください
11 | post:
12 | blank: コメントはブログ投稿に関連付ける必要があります
13 |
--------------------------------------------------------------------------------
/config/packages/test/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: fingers_crossed
5 | action_level: error
6 | handler: nested
7 | excluded_http_codes: [404, 405]
8 | channels: ["!event"]
9 | nested:
10 | type: stream
11 | path: "%kernel.logs_dir%/%kernel.environment%.log"
12 | level: debug
13 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Project documentation
2 |
3 | Table of contents:
4 |
5 | * [Configuration](configuration.md) - Where to store application configuration and environment variables
6 | * [Routing](routing.md)
7 | * [Internationalization](internationalization.md)
8 | * [Git workflow](git_workflow.md) - How to name and use git branches
9 | * [Continuous integration](continuous_integration.md)
10 | * [Testing](testing.md)
11 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/blog/create-comment.graphql:
--------------------------------------------------------------------------------
1 | mutation NewComment($parentId: ID, $postId: ID, $siteId: ID, $name: String, $email: String, $comment: String) {
2 | saveComment(newParentId: $parentId, ownerId: $postId, siteId: $siteId, name: $name, email: $email, comment: $comment) {
3 | id
4 | ownerId
5 | name
6 | email
7 | comment
8 | commentDate
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/translations/validators+intl-icu.en.yaml:
--------------------------------------------------------------------------------
1 | blog:
2 | comments:
3 | form:
4 | name:
5 | blank: Enter a name
6 | email:
7 | blank: Enter an email address
8 | format: Enter a valid email address
9 | comment:
10 | blank: Enter a comment
11 | post:
12 | blank: Comment must refer to a blog post
13 |
--------------------------------------------------------------------------------
/config/packages/nelmio_cors.yaml:
--------------------------------------------------------------------------------
1 | nelmio_cors:
2 | defaults:
3 | origin_regex: true
4 | allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
5 | allow_methods: ['HEAD', 'GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
6 | allow_headers: ['Content-Type', 'Authorization']
7 | expose_headers: ['Link']
8 | max_age: 3600
9 | allow_credentials: true
10 | paths:
11 | '^/': null
12 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/blog/comments.graphql:
--------------------------------------------------------------------------------
1 | query Comments($postId: [QueryArgument], $siteId: [QueryArgument]) {
2 | comments (ownerId: $postId, siteId: $siteId, orderBy: "commentDate ASC") {
3 | ...comment
4 | }
5 | }
6 |
7 | fragment comment on CommentInterface {
8 | id
9 | date: commentDate
10 | name
11 | email
12 | comment
13 | level
14 | parent {
15 | id
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/docs/routing.md:
--------------------------------------------------------------------------------
1 | # Routing
2 |
3 | ## Locale
4 |
5 | Symfony is setup to set the locale based on URL paths. E.g. `/ja` for Japanese. If no URL path is setup
6 | then English is set as the default locale.
7 |
8 | Setup in [annotations.yaml](../config/routes/annotations.yaml)
9 |
10 | ## Routing
11 |
12 | [Annotations](https://symfony.com/doc/current/routing.html#creating-routes-as-attributes-or-annotations) are used in controllers to define routes.
13 |
14 |
--------------------------------------------------------------------------------
/templates/bundles/W3CWebsiteTemplatesBundle/base.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@!W3CWebsiteTemplates/base.html.twig' %}
2 |
3 | {% block lang_nav %}{{ lang_nav(site.locale|default(default_locale))|raw }}{% endblock %}
4 |
5 | {% block global_nav %}{{ global_nav(site.locale|default(default_locale))|raw }}{% endblock %}
6 |
7 | {% block closing_body_scripts %}
8 |
9 | {% endblock %}
10 |
--------------------------------------------------------------------------------
/src/Query/W3C/Ecosystem/Bizdev.php:
--------------------------------------------------------------------------------
1 | setUri('/functions/bizdev');
15 | }
16 |
17 | public function getRequiredDataProviderClass(): string
18 | {
19 | return W3C::class;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/templates/press-releases/show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends site.localeData('siteLink') ? '@W3CWebsiteTemplates/pages/post.html.twig' : '@W3CWebsiteTemplates/pages/basic.html.twig' %}
2 |
3 | {% set body_classes = 'post' %}
4 |
5 | {% block feed %}
6 | {% if site.localeData('siteLink') %}
7 | {% include '@W3CWebsiteTemplates/components/styles/feed.html.twig' with { 'feed_url': '/press-releases/feed', 'feed_type': 'press release' } %}
8 | {% endif %}
9 | {% endblock %}
10 |
--------------------------------------------------------------------------------
/bin/phpunit:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | setUri('/groups/' . $type . '/' . $shortname)
15 | ->addParam('embed', true)
16 | ;
17 | }
18 |
19 | public function getRequiredDataProviderClass(): string
20 | {
21 | return W3C::class;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | config/
14 | public/
15 | src/
16 | tests/
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/blog/listing.graphql:
--------------------------------------------------------------------------------
1 | query BlogListing($site: [String]) {
2 | entry(section: "blogListing", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on blogListing_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/events/page.graphql:
--------------------------------------------------------------------------------
1 | query EventsPage($site: [String]) {
2 | entry(section: "eventsListing", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on eventsListing_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/news/listing.graphql:
--------------------------------------------------------------------------------
1 | query NewsListing($site: [String]) {
2 | entry(section: "newsListing", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on newsListing_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/templates/pages/default.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/default.html.twig' %}
2 |
3 | {% set components %}
4 | {% if page.defaultFlexibleComponents is defined and page.defaultFlexibleComponents %}
5 | {% for component in page.defaultFlexibleComponents %}
6 | {{ include('partials/defaultFlexibleComponents.html.twig') }}
7 | {% endfor %}
8 | {% endif %}
9 | {% endset %}
10 | {% set toc = table_of_contents(components, ['h2']) %}
11 |
12 | {% block components %}
13 | {{ toc.html|raw }}
14 | {% endblock %}
15 |
--------------------------------------------------------------------------------
/config/packages/prod/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: fingers_crossed
5 | action_level: error
6 | handler: nested
7 | excluded_http_codes: [ 404, 405 ]
8 | channels: [ "!php" ]
9 | nested:
10 | type: stream
11 | path: "%kernel.logs_dir%/%kernel.environment%.log"
12 | level: debug
13 | console:
14 | type: console
15 | process_psr_3_messages: false
16 | channels: [ "!event", "!doctrine" ]
17 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/newsletters/collection.graphql:
--------------------------------------------------------------------------------
1 | query NewsletterCollection($site: [String], $year: [String], $limit: Int, $offset: Int) {
2 | total: entryCount(section: "newsletter", site: $site, postDate: $year)
3 | entries(section: "newsletter", site: $site, postDate: $year, limit: $limit, offset: $offset, orderBy: "postDate desc") {
4 | title
5 | date: postDate
6 | year: postDate@formatDateTime(format: "Y")
7 | month: postDate@formatDateTime(format: "m")
8 | day: postDate@formatDateTime(format: "d")
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/newsletters/listing.graphql:
--------------------------------------------------------------------------------
1 | query NewslettersListing($site: [String]) {
2 | entry(section: "newsletterArchive", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on newsletterArchive_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/feeds/events.graphql:
--------------------------------------------------------------------------------
1 | query Events($site: [String], $limit: Int) {
2 | entries(section: "events", site: $site, limit: $limit, orderBy: "postDate desc") {
3 | ... on events_default_Entry {
4 | ...listingEvent
5 | defaultFlexibleComponents {
6 | ...defaultFlexibleComponents
7 | }
8 | }
9 | ... on external_Entry {
10 | ...listingExternalEvent
11 | }
12 | ... on entryContentIsACraftPage_Entry {
13 | ...listingPageEvent
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/press-releases/listing.graphql:
--------------------------------------------------------------------------------
1 | query PressReleasesListing($site: [String]) {
2 | entry(section: "pressReleasesListing", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on pressReleasesListing_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/breadcrumbs.graphql:
--------------------------------------------------------------------------------
1 | fragment breadcrumbs on EntryInterface {
2 | title
3 | uri
4 | parent {
5 | title
6 | uri
7 | parent {
8 | title
9 | uri
10 | parent {
11 | title
12 | uri
13 | parent {
14 | title
15 | uri
16 | parent {
17 | title
18 | uri
19 | }
20 | }
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/config/packages/notifier.yaml:
--------------------------------------------------------------------------------
1 | framework:
2 | notifier:
3 | #chatter_transports:
4 | # slack: '%env(SLACK_DSN)%'
5 | # telegram: '%env(TELEGRAM_DSN)%'
6 | #texter_transports:
7 | # twilio: '%env(TWILIO_DSN)%'
8 | # nexmo: '%env(NEXMO_DSN)%'
9 | channel_policy:
10 | # use chat/slack, chat/telegram, sms/twilio or sms/nexmo
11 | urgent: ['email']
12 | high: ['email']
13 | medium: ['email']
14 | low: ['email']
15 | admin_recipients:
16 | - { email: admin@example.com }
17 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/ecosystems/testimonials.graphql:
--------------------------------------------------------------------------------
1 | query testimonials($ecosystemId: [QueryArgument]) {
2 | entries(section: "testimonial", ecosystems: $ecosystemId, site: "*") {
3 | id
4 | language
5 | ... on testimonial_default_Entry {
6 | quote: quoteForCarousel
7 | author: authorName
8 | authorJobTitle
9 | organization: authorOrganization
10 | logo: organizationLogo {
11 | ... on publicS3Bucket_Asset {
12 | url
13 | }
14 | }
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/public/index.php:
--------------------------------------------------------------------------------
1 | bootEnv(dirname(__DIR__) . '/.env');
11 |
12 | if ($_SERVER['APP_DEBUG']) {
13 | umask(0000);
14 |
15 | Debug::enable();
16 | }
17 |
18 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
19 | $request = Request::createFromGlobals();
20 | $response = $kernel->handle($request);
21 | $response->send();
22 | $kernel->terminate($request, $response);
23 |
--------------------------------------------------------------------------------
/config/packages/fos_http_cache.yaml:
--------------------------------------------------------------------------------
1 | fos_http_cache:
2 | flash_message:
3 | enabled: true
4 | tags:
5 | enabled: true
6 | response_header: Cache-Tag
7 | proxy_client:
8 | default: noop
9 | noop: ~
10 | cache_control:
11 | defaults:
12 | overwrite: false
13 | rules:
14 | # match everything to set defaults
15 | -
16 | match:
17 | path: ^/
18 | headers:
19 | cache_control:
20 | public: true
21 | s_maxage: 86400
22 | etag: true
23 |
--------------------------------------------------------------------------------
/docs/front-end-integration/README.md:
--------------------------------------------------------------------------------
1 | # Front-end integration
2 |
3 | The following is an overview on how to integrate HTML/CSS templates with content (from a CMS or other data
4 | sources) in Symfony to create finished web pages with real content. We are using the
5 | [Strata](https://github.com/strata/frontend) library to help integrate with headless CMS and other data
6 | sources. CraftCMS uses [GraphQL](https://graphql.org/learn/) for all API queries.
7 |
8 | * [Routing](routing.md)
9 | * [Retrieving data](retrieving-data.md)
10 | * [GraphQL queries for CraftCMS](craftcms-graphql.md)
11 | * [Templating](templating.md) (todo)
12 | * [Testing](testing.md) (todo)
13 |
--------------------------------------------------------------------------------
/config/packages/dev/monolog.yaml:
--------------------------------------------------------------------------------
1 | monolog:
2 | handlers:
3 | main:
4 | type: stream
5 | path: "%kernel.logs_dir%/%kernel.environment%.log"
6 | level: debug
7 | channels: ["!event"]
8 | # uncomment to get logging in your browser
9 | # you may have to allow bigger header sizes in your Web server configuration
10 | #firephp:
11 | # type: firephp
12 | # level: info
13 | #chromephp:
14 | # type: chromephp
15 | # level: info
16 | console:
17 | type: console
18 | process_psr_3_messages: false
19 | channels: ["!event", "!doctrine", "!console"]
20 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/listingEvent.graphql:
--------------------------------------------------------------------------------
1 | fragment listingEvent on events_default_Entry {
2 | id
3 | typeHandle
4 | slug
5 | uri
6 | title
7 | date: postDate
8 | start: startDatetime
9 | end: endDatetime
10 | tz: startDatetime@formatDateTime(format: "e")
11 | year: startDatetime @formatDateTime(format: "Y")
12 | category: blogCategories {
13 | id
14 | slug
15 | uri
16 | title
17 | }
18 | type: eventType {
19 | id
20 | slug
21 | title
22 | }
23 | excerpt: eventExcerpt
24 | thumbnailImage {
25 | ...thumbnailImage
26 | }
27 | thumbnailAltText
28 | location
29 | host
30 | }
31 |
--------------------------------------------------------------------------------
/config/packages/framework.yaml:
--------------------------------------------------------------------------------
1 | # see https://symfony.com/doc/current/reference/configuration/framework.html
2 | framework:
3 | secret: '%env(APP_SECRET)%'
4 | trusted_proxies: '%env(TRUSTED_PROXIES)%'
5 | #csrf_protection: true
6 | #http_method_override: true
7 |
8 | # Enables session support. Note that the session will ONLY be started if you read or write from it.
9 | # Remove or comment this section to explicitly disable session support.
10 | session:
11 | handler_id: null
12 | cookie_secure: auto
13 | cookie_samesite: lax
14 | storage_factory_id: session.storage.factory.native
15 |
16 | #esi: true
17 | #fragments: true
18 | php_errors:
19 | log: true
20 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/listingExternalEvent.graphql:
--------------------------------------------------------------------------------
1 | fragment listingExternalEvent on external_Entry {
2 | id
3 | typeHandle
4 | slug
5 | uri
6 | title
7 | date: postDate
8 | start: startDatetime
9 | end: endDatetime
10 | tz: startDatetime@formatDateTime(format: "e")
11 | year: startDatetime @formatDateTime(format: "Y")
12 | category: blogCategories {
13 | id
14 | slug
15 | uri
16 | title
17 | }
18 | type: eventType {
19 | id
20 | slug
21 | title
22 | }
23 | excerpt: eventExcerpt
24 | thumbnailImage {
25 | ...thumbnailImage
26 | }
27 | thumbnailAltText
28 | location
29 | host
30 | urlLink
31 | }
32 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Blog/Comment.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/blog/comment.graphql')
22 | ->setRootPropertyPath('[comment]')
23 | ->addVariable('id', '' . $id)
24 | // ->enableCache($cacheLifetime)
25 | ;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/templates/newsletters/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/listing.html.twig' %}
2 |
3 | {% set extra_main_attributes = 'data-anchor="no"' %}
4 |
5 | {% block filters %}
6 | {{ include('@W3CWebsiteTemplates/components/listings/newsletters/filters.html.twig') }}
7 | {% endblock %}
8 |
9 | {% block list %}
10 |
11 | {{ 'pagination.summary'|trans({
12 | 'page': entries.pagination.page,
13 | 'from': entries.pagination.from,
14 | 'to': entries.pagination.to
15 | }, 'w3c_website_templates_bundle') }}
16 |
17 |
18 | {# use same template as news #}
19 | {{ include('@W3CWebsiteTemplates/components/listings/news/list.html.twig') }}
20 | {% endblock %}
21 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/listingPageEvent.graphql:
--------------------------------------------------------------------------------
1 | fragment listingPageEvent on entryContentIsACraftPage_Entry {
2 | id
3 | typeHandle
4 | slug
5 | uri
6 | title
7 | date: postDate
8 | start: startDatetime
9 | end: endDatetime
10 | tz: startDatetime@formatDateTime(format: "e")
11 | year: startDatetime @formatDateTime(format: "Y")
12 | category: blogCategories {
13 | id
14 | slug
15 | uri
16 | title
17 | }
18 | type: eventType {
19 | id
20 | slug
21 | title
22 | }
23 | location
24 | host
25 | page: eventPage {
26 | uri
27 | }
28 | excerpt: eventExcerpt
29 | thumbnailImage {
30 | ...thumbnailImage
31 | }
32 | thumbnailAltText
33 | }
34 |
--------------------------------------------------------------------------------
/templates/ecosystems/show.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/ecosystem.html.twig' %}
2 |
3 | {% block components %}
4 | {% for component in page.ecosystemsFlexibleComponents %}
5 | {{ include('partials/ecosystemsFlexibleComponents.html.twig') }}
6 | {% endfor %}
7 | {% endblock %}
8 | {% block bottom_components %}
9 | {% for component in page.ecosystemsBottomFlexibleComponents %}
10 | {{ include('partials/ecosystemsFlexibleComponents.html.twig') }}
11 | {% endfor %}
12 | {% endblock %}
13 | {% block pre_footer %}
14 | {{ include('@W3CWebsiteTemplates/components/styles/feed.html.twig', {
15 | 'feed_url': path('app_feed_ecosystem', {'slug': page.slug}),
16 | 'feed_type': page.title
17 | }) }}
18 | {% endblock %}
19 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/feeds/news.graphql:
--------------------------------------------------------------------------------
1 | query news($site: [String], $limit: Int) {
2 | entries(section: "newsArticles", site: $site, limit: $limit, orderBy: "postDate desc") {
3 | id
4 | slug
5 | uri
6 | title
7 | year: postDate@formatDateTime(format: "Y")
8 | date: postDate
9 | dateUpdated
10 | ... on newsArticles_default_Entry {
11 | excerpt
12 | defaultFlexibleComponents(orderBy: "sortOrder") {
13 | ...defaultFlexibleComponents
14 | }
15 | }
16 | ... on newsArticles_importedEntries_Entry {
17 | excerpt
18 | pageContent
19 | }
20 | }
21 | }
22 |
23 | fragment contentImage on AssetInterface {
24 | src: url(width: 580)
25 | extension
26 | }
27 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Blog/Comments.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/blog/comments.graphql')
22 | ->setRootPropertyPath('[comments]')
23 | ->addVariable('postId', $id)
24 | ->addVariable('siteId', $siteId)
25 | ->cache($cacheLifetime)
26 | ;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/Query/W3C/Ecosystem/BizdevLead.php:
--------------------------------------------------------------------------------
1 | setUri('/users/' . $hash);
16 | }
17 |
18 | public function getRequiredDataProviderClass(): string
19 | {
20 | return W3C::class;
21 | }
22 |
23 | public function getMapping(): MappingStrategyInterface|array
24 | {
25 | return [
26 | '[name]' => '[name]',
27 | '[work_title]' => '[work-title]',
28 | '[phone]' => '[phone]',
29 | '[email]' => '[email]',
30 | ];
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/singles-breadcrumbs.graphql:
--------------------------------------------------------------------------------
1 | query SinglesBreadcrumbs($site: [String]) {
2 | homepage: entry(section: "homepage", site: $site) {
3 | slug
4 | title
5 | uri
6 | }
7 | blog: entry(section: "blogListing", site: $site) {
8 | slug
9 | title
10 | uri
11 | }
12 | pressReleases: entry(section: "pressReleasesListing", site: $site) {
13 | slug
14 | title
15 | uri
16 | }
17 | events: entry(section: "eventsListing", site: $site) {
18 | slug
19 | title
20 | uri
21 | }
22 | news: entry(section: "newsListing", site: $site) {
23 | slug
24 | title
25 | uri
26 | }
27 | ecosystems: entry(section: "ecosystemsLandingPage", site: $site) {
28 | slug
29 | title
30 | uri
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/feeds/press-releases.graphql:
--------------------------------------------------------------------------------
1 | query pressReleases($site: [String], $limit: Int) {
2 | entries(section: "pressReleases", site: $site, limit: $limit, orderBy: "postDate desc") {
3 | id
4 | slug
5 | uri
6 | title
7 | year: postDate@formatDateTime(format: "Y")
8 | date: postDate
9 | dateUpdated
10 | ... on pressReleases_default_Entry {
11 | excerpt
12 | defaultFlexibleComponents(orderBy: "sortOrder") {
13 | ...defaultFlexibleComponents
14 | }
15 | }
16 | ... on importedEntries_Entry {
17 | excerpt
18 | pageContent
19 | }
20 | }
21 | comments(site: $site) {
22 | ownerId
23 | }
24 | }
25 |
26 | fragment contentImage on AssetInterface {
27 | src: url(width: 580)
28 | extension
29 | }
30 |
--------------------------------------------------------------------------------
/.env.local.dist:
--------------------------------------------------------------------------------
1 | # Application environment (dev, staging, prod)
2 | APP_ENV=dev
3 | APP_URL=https://w3c-website-frontend.ddev.site
4 |
5 | # W3C API API key
6 | # see https://w3c.github.io/w3c-api/
7 | W3C_API_KEY="op://Clients/W3C API URLs/W3C_API_TOKEN"
8 |
9 | # Craft CMS API tokens
10 | CRAFTCMS_API_URL="https://cms-dev.w3.org/api"
11 | CRAFTCMS_API_READ_TOKEN="op://Clients/W3C API URLs/CRAFTCMS_API_TOKEN_DEV"
12 | CRAFTCMS_API_PUBLISH_TOKEN=""
13 |
14 | # Point assets to W3C CDN for local dev
15 | ASSETS_WEBSITE_2021=https://www.w3.org/assets/website-2021/
16 |
17 | # Other Symfony configuration
18 | MAILER_DRIVER="smtp"
19 | MAILER_HOST="127.0.0.1"
20 | MAILER_PORT="1025"
21 | MAILER_URL="smtp://127.0.0.1:1025"
22 | MAILER_WEB_URL="https://w3c-website-frontend.ddev.site:8026"
23 | MAILER_AUTH_MODE=""
24 | MAILER_PASSWORD=""
25 | MAILER_USERNAME=""
26 | MAILER_CATCHER="1"
27 | MAILER_DSN="smtp://127.0.0.1:1025"
28 |
--------------------------------------------------------------------------------
/config/packages/security.yaml:
--------------------------------------------------------------------------------
1 | security:
2 | # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
3 | providers:
4 | users_in_memory: { memory: null }
5 | firewalls:
6 | dev:
7 | pattern: ^/(_(profiler|wdt)|css|images|js)/
8 | security: false
9 | main:
10 | lazy: true
11 | provider: users_in_memory
12 |
13 | # activate different ways to authenticate
14 | # https://symfony.com/doc/current/security.html#firewalls-authentication
15 |
16 | # https://symfony.com/doc/current/security/impersonating_user.html
17 | # switch_user: true
18 | # Easy way to control access for large sections of your site
19 | # Note: Only the *first* access control that matches will be used
20 | access_control:
21 | # - { path: ^/admin, roles: ROLE_ADMIN }
22 | # - { path: ^/profile, roles: ROLE_USER }
23 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/staff/alumni.graphql:
--------------------------------------------------------------------------------
1 | query AlumniListing($site: [String]) {
2 | entry(section: "alumniListing", site: $site) {
3 | id
4 | slug
5 | title
6 | uri
7 | expiryDate
8 | breadcrumbs: parent {
9 | ...breadcrumbs
10 | }
11 | ... on alumniListing_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | lead: pageLead
18 | }
19 | }
20 | total: entryCount(section: "alumni", site: $site)
21 | entries(section: "alumni", site: $site, orderBy: "familyName asc, title asc") {
22 | ... on alumni_default_Entry {
23 | slug
24 | given: givenName
25 | last: familyName
26 | start: startDate
27 | end: endDate
28 | biography: shortBiography
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Service/CraftCMS.php:
--------------------------------------------------------------------------------
1 | setAuthorization($apiKey);
26 | }
27 |
28 | /**
29 | * Set API authorization token to use with all requests
30 | *
31 | * @param string $token
32 | */
33 | public function setAuthorization(string $token)
34 | {
35 | $this->setDefaultOptions([
36 | 'auth_bearer' => $token
37 | ]);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Query/W3C/Healthcheck.php:
--------------------------------------------------------------------------------
1 | setUri('healthcheck')
20 | // ->disableCache()
21 | ;
22 | }
23 |
24 | public function getRequiredDataProviderClass(): string
25 | {
26 | return W3C::class;
27 | }
28 |
29 | /**
30 | * Check all services are online
31 | *
32 | * @return bool
33 | * @throws \Strata\Data\Exception\MapperException
34 | */
35 | public function isHealthy(): bool
36 | {
37 | $data = $this->get();
38 | if ($data['app'] === true && $data['database'] === true) {
39 | return true;
40 | }
41 |
42 | return false;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/defaultFlexibleComponents.graphql:
--------------------------------------------------------------------------------
1 | fragment defaultFlexibleComponents on defaultFlexibleComponents_MatrixField {
2 | ... on textComponent_Entry {
3 | typeHandle
4 | contentField
5 | }
6 | ... on blockquoteComponent_Entry {
7 | typeHandle
8 | quoteText
9 | citation
10 | }
11 | ...on imageMediaComponent_Entry {
12 | typeHandle
13 | imageMedia {
14 | ...contentImage
15 | }
16 | altText
17 | figureCaption
18 | informativeOrDecorative
19 | }
20 | ...on videoMediaComponent_Entry {
21 | typeHandle
22 | videoTitle
23 | videoUrl {
24 | url
25 | image
26 | imageWidth
27 | imageHeight
28 | code
29 | width
30 | height
31 | aspectRatio
32 | providerName
33 | }
34 | videoCaption
35 | linkToVideoTranscript
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/config/routes/annotations.yaml:
--------------------------------------------------------------------------------
1 | controllers:
2 | resource: ../../src/Controller/
3 | type: attribute
4 | prefix:
5 | af: '/af'
6 | ar: '/ar'
7 | bg: '/bg'
8 | cs: '/cs'
9 | da: '/da'
10 | de: '/de'
11 | el: '/el'
12 | es: '/es'
13 | et: '/et'
14 | fi: '/fi'
15 | fr: '/fr'
16 | ga: '/ga'
17 | hi: '/hi'
18 | hu: '/hu'
19 | it: '/it'
20 | ja: '/ja'
21 | ko: '/ko'
22 | lt: '/lt'
23 | lv: '/lv'
24 | mt: '/mt'
25 | nl: '/nl'
26 | pt-br: '/pt-br'
27 | pt: '/pt'
28 | ro: '/ro'
29 | ru: '/ru'
30 | sk: '/sk'
31 | sl: '/sl'
32 | sv: '/sv'
33 | zh-hans: '/zh-hans'
34 | zu: '/zu'
35 | en: '' # safety net: this is last to ensure a URL containing a locale is not considered as a parameter for an English route
36 |
37 | kernel:
38 | resource: ../../src/Kernel.php
39 | type: attribute
40 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/home/recent-activities.graphql:
--------------------------------------------------------------------------------
1 | query RecentActivities($site: [String]) {
2 | recentEntries: entries(site: $site, section: ["blogPosts", "newsArticles", "pressReleases"], limit: 4, orderBy: "postDate DESC") {
3 | id
4 | slug
5 | sectionHandle
6 | typeHandle
7 | title
8 | uri
9 | url
10 | year: postDate @formatDateTime(format: "Y")
11 | ... on blogPosts_default_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | }
18 | ... on newsArticles_default_Entry {
19 | excerpt
20 | thumbnailImage {
21 | ...thumbnailImage
22 | }
23 | thumbnailAltText
24 | }
25 | ... on pressReleases_default_Entry {
26 | excerpt
27 | thumbnailImage {
28 | ...thumbnailImage
29 | }
30 | thumbnailAltText
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Blog/CreateComment.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/blog/create-comment.graphql')
27 | ->setRootPropertyPath('[saveComment]')
28 | ->addVariable('postId', $id)
29 | ->addVariable('siteId', $siteId)
30 | ->addVariable('name', $name)
31 | ->addVariable('email', $email)
32 | ->addVariable('comment', $comment)
33 | ->addVariable('parentId', $parentId)
34 | ;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Feeds/Comments.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/feeds/comments.graphql')
32 | ->setRootPropertyPath('[comments]')
33 | ->addVariable('ownerId', $postIds)
34 | ;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/templates/blog/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/listing.html.twig' %}
2 |
3 | {% set extra_main_attributes = 'data-anchor="no"' %}
4 |
5 | {% block filters %}
6 | {{ include('@W3CWebsiteTemplates/components/listings/blog/filters.html.twig') }}
7 | {% endblock %}
8 |
9 | {% block list %}
10 |
11 | {{ 'pagination.summary'|trans({
12 | 'page': entries.pagination.page,
13 | 'from': entries.pagination.from,
14 | 'to': entries.pagination.to
15 | }, 'w3c_website_templates_bundle') }}
16 |
17 |
18 | {{ include('@W3CWebsiteTemplates/components/listings/blog/list.html.twig') }}
19 | {% endblock %}
20 |
21 | {% block pre_footer %}
22 | {% embed '@W3CWebsiteTemplates/components/pre-footer.html.twig' %}
23 | {% block content %}
24 | {% include '@W3CWebsiteTemplates/components/styles/feed.html.twig' with { 'feed_url': path('app_feed_blog'), 'feed_type': 'blog' } %}
25 | {% endblock %}
26 | {% endembed %}
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/templates/news/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/listing.html.twig' %}
2 |
3 | {% set extra_main_attributes = 'data-anchor="no"' %}
4 |
5 | {% block filters %}
6 | {{ include('@W3CWebsiteTemplates/components/listings/news/filters.html.twig') }}
7 | {% endblock %}
8 |
9 | {% block list %}
10 |
11 | {{ 'pagination.summary'|trans({
12 | 'page': entries.pagination.page,
13 | 'from': entries.pagination.from,
14 | 'to': entries.pagination.to
15 | }, 'w3c_website_templates_bundle') }}
16 |
17 |
18 | {{ include('@W3CWebsiteTemplates/components/listings/news/list.html.twig') }}
19 | {% endblock %}
20 |
21 | {% block pre_footer %}
22 | {% embed '@W3CWebsiteTemplates/components/pre-footer.html.twig' %}
23 | {% block content %}
24 | {% include '@W3CWebsiteTemplates/components/styles/feed.html.twig' with { 'feed_url': path('app_feed_news'), 'feed_type': 'news' } %}
25 | {% endblock %}
26 | {% endembed %}
27 | {% endblock %}
28 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Feeds/News.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/feeds/news.graphql')
29 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/defaultFlexibleComponents.graphql')
30 | ->setRootPropertyPath('[entries]')
31 | ->addVariable('site', $siteHandle)
32 | ->addVariable('limit', $limit)
33 | ->cacheTags(['newsArticles'])
34 | ;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # NPM
2 | node_modules
3 | npm-debug.log
4 |
5 | # SASS
6 | .sass_cache
7 |
8 | # Caches
9 | .phplint-cache
10 |
11 | #PHPStorm
12 | .idea
13 |
14 | ###> symfony/framework-bundle ###
15 | /.env.local
16 | /.env.local.php
17 | /.env.*.local
18 | /config/secrets/prod/prod.decrypt.private.php
19 | /public/bundles/
20 | /var/
21 | /vendor/
22 | ###< symfony/framework-bundle ###
23 |
24 | ###> symfony/phpunit-bridge ###
25 | .phpunit
26 | .phpunit.result.cache
27 | /phpunit.xml
28 | ###< symfony/phpunit-bridge ###
29 |
30 | ###> squizlabs/php_codesniffer ###
31 | /.phpcs-cache
32 | /phpcs.xml
33 | ###< squizlabs/php_codesniffer ###
34 |
35 | ###> phpunit/phpunit ###
36 | /phpunit.xml
37 | .phpunit.result.cache
38 | ###< phpunit/phpunit ###
39 |
40 | ###> PHPStorm graphql ###
41 | /.graphqlconfig
42 | /schema.graphql
43 | ###< PHPStorm graphql ###
44 |
45 | test-cache-clear.php
46 |
47 | # YAML file that ignores peer and host
48 | # Gets ignored so it doesn't go on the dev server on deployment
49 | config/packages/dev/http_client.yaml
50 |
51 | # Ignore design system assets symlink
52 | public/assets
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | tests
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | src
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/press-releases/collection.graphql:
--------------------------------------------------------------------------------
1 | query PressReleasesCollection($site: [String], $before: String, $after: String, $limit: Int, $offset: Int) {
2 | total: entryCount(section: "pressReleases", site: $site, before: $before, after: $after)
3 | entries(section: "pressReleases", site: $site, before: $before, after: $after, limit: $limit, offset: $offset, orderBy: "postDate desc") {
4 | id
5 | slug
6 | uri
7 | title
8 | date: postDate
9 | year: postDate@formatDateTime(format: "Y")
10 | ... on pressReleases_default_Entry {
11 | excerpt
12 | thumbnailImage {
13 | ...thumbnailImage
14 | }
15 | thumbnailAltText
16 | }
17 | ... on importedEntries_Entry {
18 | excerpt
19 | thumbnailImage {
20 | ...thumbnailImage
21 | }
22 | thumbnailAltText
23 | }
24 | }
25 | }
26 |
27 | fragment thumbnailImage on AssetInterface {
28 | url(transform: "size360x270")
29 | srcset(sizes: ["580w"])
30 | }
31 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Feeds/PressReleases.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/feeds/press-releases.graphql')
29 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/defaultFlexibleComponents.graphql')
30 | ->setRootPropertyPath('[entries]')
31 | ->addVariable('site', $siteHandle)
32 | ->addVariable('limit', $limit)
33 | ->cacheTags(['pressReleases'])
34 | ;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/news/collection.graphql:
--------------------------------------------------------------------------------
1 | query NewsCollection($site: [String], $before: String, $after: String, $search: String, $limit: Int, $offset: Int) {
2 | total: entryCount(section: "newsArticles", site: $site, before: $before, after: $after, search: $search)
3 | entries(section: "newsArticles", site: $site, before: $before, after: $after, search: $search, limit: $limit, offset: $offset, orderBy: "postDate desc") {
4 | id
5 | slug
6 | uri
7 | title
8 | date: postDate
9 | year: postDate@formatDateTime(format: "Y")
10 | ... on newsArticles_default_Entry {
11 | excerpt
12 | thumbnailImage {
13 | ...thumbnailImage
14 | }
15 | thumbnailAltText
16 | }
17 | ... on newsArticles_importedEntries_Entry {
18 | excerpt
19 | thumbnailImage {
20 | ...thumbnailImage
21 | }
22 | thumbnailAltText
23 | }
24 | }
25 | }
26 |
27 | fragment thumbnailImage on AssetInterface {
28 | url(transform: "size360x270")
29 | srcset(sizes: ["580w"])
30 | }
31 |
--------------------------------------------------------------------------------
/templates/press-releases/index.html.twig:
--------------------------------------------------------------------------------
1 | {% extends '@W3CWebsiteTemplates/pages/listing.html.twig' %}
2 |
3 | {% set extra_main_attributes = 'data-anchor="no"' %}
4 |
5 | {% block filters %}
6 | {{ include('@W3CWebsiteTemplates/components/listings/press-releases/filters.html.twig') }}
7 | {% endblock %}
8 |
9 | {% block list %}
10 |
11 | {{ 'pagination.summary'|trans({
12 | 'page': entries.pagination.page,
13 | 'from': entries.pagination.from,
14 | 'to': entries.pagination.to
15 | }, 'w3c_website_templates_bundle') }}
16 |
17 |
18 | {{ include('@W3CWebsiteTemplates/components/listings/press-releases/list.html.twig') }}
19 | {% endblock %}
20 |
21 | {% block pre_footer %}
22 | {% embed '@W3CWebsiteTemplates/components/pre-footer.html.twig' %}
23 | {% block content %}
24 | {% include '@W3CWebsiteTemplates/components/styles/feed.html.twig' with { 'feed_url': path('app_feed_pressreleases'), 'feed_type': 'press releases' } %}
25 | {{ parent() }}
26 | {% endblock %}
27 | {% endembed %}
28 | {% endblock %}
29 |
--------------------------------------------------------------------------------
/config/packages/nyholm_psr7.yaml:
--------------------------------------------------------------------------------
1 | services:
2 | # Register nyholm/psr7 services for autowiring with PSR-17 (HTTP factories)
3 | Psr\Http\Message\RequestFactoryInterface: '@nyholm.psr7.psr17_factory'
4 | Psr\Http\Message\ResponseFactoryInterface: '@nyholm.psr7.psr17_factory'
5 | Psr\Http\Message\ServerRequestFactoryInterface: '@nyholm.psr7.psr17_factory'
6 | Psr\Http\Message\StreamFactoryInterface: '@nyholm.psr7.psr17_factory'
7 | Psr\Http\Message\UploadedFileFactoryInterface: '@nyholm.psr7.psr17_factory'
8 | Psr\Http\Message\UriFactoryInterface: '@nyholm.psr7.psr17_factory'
9 |
10 | # Register nyholm/psr7 services for autowiring with HTTPlug factories
11 | Http\Message\MessageFactory: '@nyholm.psr7.httplug_factory'
12 | Http\Message\RequestFactory: '@nyholm.psr7.httplug_factory'
13 | Http\Message\ResponseFactory: '@nyholm.psr7.httplug_factory'
14 | Http\Message\StreamFactory: '@nyholm.psr7.httplug_factory'
15 | Http\Message\UriFactory: '@nyholm.psr7.httplug_factory'
16 |
17 | nyholm.psr7.psr17_factory:
18 | class: Nyholm\Psr7\Factory\Psr17Factory
19 |
20 | nyholm.psr7.httplug_factory:
21 | class: Nyholm\Psr7\Factory\HttplugFactory
22 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Taxonomies/Tags.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/taxonomies/tags.graphql')
29 | ->addVariable('site', $siteHandle)
30 | ->addVariable('handle', $handle)
31 | ->setRootPropertyPath('[tags]')
32 | ->cache($cacheLifetime)
33 | ;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Feeds/Blog.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/feeds/blog.graphql')
29 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/defaultFlexibleComponents.graphql')
30 | ->setRootPropertyPath('[entries]')
31 | ->addVariable('site', $siteHandle)
32 | ->addVariable('limit', $limit)
33 | ->addVariable('category', $category)
34 | ->addVariable('tag', $tag)
35 | ->cacheTags(['blogPosts'])
36 | ;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Taxonomies/Categories.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/taxonomies/categories.graphql')
29 | ->addVariable('site', $siteHandle)
30 | ->addVariable('handle', $handle)
31 | ->setRootPropertyPath('[categories]')
32 | ->cache($cacheLifetime)
33 | ;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/rector.php:
--------------------------------------------------------------------------------
1 | withPaths([
12 | __DIR__ . '/config',
13 | __DIR__ . '/public',
14 | __DIR__ . '/src',
15 | __DIR__ . '/tests',
16 | __DIR__ . '/templates',
17 | ])
18 | // uncomment to reach your current PHP version
19 | // ->withPhpSets()
20 | ->withTypeCoverageLevel(0)
21 | ->withSymfonyContainerXml(__DIR__ . '/var/cache/dev/App_KernelDevDebugContainer.xml')
22 | ->withSets(
23 | [
24 | SymfonySetList::SYMFONY_71,
25 | SymfonySetList::SYMFONY_CODE_QUALITY,
26 | SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
27 | SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES,
28 | SymfonySetList::CONFIGS,
29 | ]
30 | )
31 | ->withSymfonyContainerPhp(__DIR__ . '/tests/symfony-container.php')
32 | ->registerService(SymfonyRoutesProvider::class, SymfonyRoutesProviderInterface::class)
33 | ;
34 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Taxonomies/GroupInfo.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/taxonomies/group-info.graphql')
32 | ->addVariable('site', $siteHandle)
33 | ->addVariable('slug', $slug)
34 | ->setRootPropertyPath('[category]')
35 | ->cache($cacheLifetime);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/config/bundles.php:
--------------------------------------------------------------------------------
1 | ['all' => true],
5 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],
6 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true],
7 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true],
8 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true],
9 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],
10 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true],
11 | Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true],
12 | W3C\WebsiteTemplatesBundle\W3CWebsiteTemplatesBundle::class => ['all' => true],
13 | FOS\HttpCacheBundle\FOSHttpCacheBundle::class => ['all' => true],
14 | Strata\SymfonyBundle\StrataBundle::class => ['all' => true],
15 | Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
16 | Exercise\HTMLPurifierBundle\ExerciseHTMLPurifierBundle::class => ['all' => true],
17 | Chrisguitarguy\RequestId\ChrisguitarguyRequestIdBundle::class => ['all' => true],
18 | Ekreative\HealthCheckBundle\EkreativeHealthCheckBundle::class => ['all' => true],
19 | ];
20 |
--------------------------------------------------------------------------------
/src/Query/W3C/Ecosystem/Members.php:
--------------------------------------------------------------------------------
1 | setUri('/ecosystems/' . $slug . '/member-organizations')
17 | ->addParam('items', $perPage)
18 | ->addParam('embed', true)
19 | ->addParam('page', $page)
20 | ->setRootPropertyPath('[_embedded][affiliations]')
21 | ->setCurrentPage('[page]')
22 | ->setTotalResults('[total]')
23 | ->setResultsPerPage('[limit]')
24 | // ->disableCache()
25 | ;
26 | }
27 |
28 | public function getRequiredDataProviderClass(): string
29 | {
30 | return W3C::class;
31 | }
32 |
33 | public function getMapping(): MappingStrategyInterface|array
34 | {
35 | return [
36 | '[name]' => '[name]',
37 | '[logo]' => '[_links][logo][href]'
38 | ];
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/docs/front-end-integration/matrix-flexible-components.md:
--------------------------------------------------------------------------------
1 | # Matrix: flexible components
2 |
3 | _Information from CraftCMS Support:_
4 |
5 | If you’re looking to get content from a Rich Text field within a Matrix block, you'll need the entry type, Matrix field
6 | handle, Matrix block type, and Matrix block field handle for the query like this:
7 |
8 | ```graphql
9 | query {
10 | entries(section: "blog") {
11 | ... on blog_blog_Entry {
12 | postBlocks {
13 | ... on postBlocks_text_BlockType {
14 | body
15 | }
16 | }
17 | }
18 | }
19 | }
20 | ```
21 |
22 | This is for a blog section entry with a postBlocks Matrix field with a body Rich Text field that’s in a text block type.
23 |
24 | Each of these bits and pieces should be discoverable via autocomplete or the Explorer pane in Craft’s GraphiQL interface.
25 |
26 | 
27 |
28 | 
29 |
30 | This is what that Matrix field’s configuration looks like in the Craft control panel.
31 |
32 | 
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Newsletters/Entry.php:
--------------------------------------------------------------------------------
1 | add(new DateInterval('P1D'));
33 |
34 | $this->setGraphQLFromFile(__DIR__ . '/../graphql/newsletters/entry.graphql')
35 | ->setRootPropertyPath('[entry]')
36 | ->addVariable('site', $siteHandle)
37 | ->addVariable('date', ['and', '>=' . $date->format('Y-m-d'), '<' . $nextDay->format('Y-m-d')])
38 | ->cacheTags(['newsletter'])
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Query/W3C/Ecosystem/Groups.php:
--------------------------------------------------------------------------------
1 | setUri('/ecosystems/' . $slug . '/groups')
16 | ->addParam('items', $perPage)
17 | ->addParam('embed', true)
18 | ->addParam('page', $page)
19 | ->setRootPropertyPath('[_embedded][groups]')
20 | ->setCurrentPage('[page]')
21 | ->setTotalResults('[total]')
22 | ->setResultsPerPage('[limit]');
23 | // ->disableCache();
24 | }
25 |
26 | public function getRequiredDataProviderClass(): string
27 | {
28 | return W3C::class;
29 | }
30 |
31 | public function getMapping(): MappingStrategyInterface|array
32 | {
33 | return [
34 | '[name]' => '[name]',
35 | '[type]' => '[type]',
36 | '[description]' => '[description]',
37 | '[url]' => '[_links][homepage][href]',
38 | ];
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Query/W3C/Home/Members.php:
--------------------------------------------------------------------------------
1 | setUri('/affiliations')
17 | ->addParam('is-member', true)
18 | ->addParam('with-logo', true)
19 | ->addParam('items', $perPage)
20 | ->addParam('embed', true)
21 | ->addParam('page', $page)
22 | ->setRootPropertyPath('[_embedded][affiliations]')
23 | ->setCurrentPage('[page]')
24 | ->setTotalResults('[total]')
25 | ->setResultsPerPage('[limit]')
26 | ->cacheTag('members')
27 | ;
28 | }
29 |
30 | public function getRequiredDataProviderClass(): string
31 | {
32 | return W3C::class;
33 | }
34 |
35 | public function getMapping(): MappingStrategyInterface|array
36 | {
37 | return [
38 | '[name]' => '[name]',
39 | '[logo]' => '[_links][logo][href]'
40 | ];
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/config/packages/chrisguitarguy_request_id.yaml:
--------------------------------------------------------------------------------
1 | chrisguitarguy_request_id:
2 | # The header which the bundle inspects for the incoming request ID
3 | # if this is not set an ID will be generated and set at this header
4 | request_header: X-Request-Id
5 |
6 | # Whether or not to trust the incoming request header. This is turned
7 | # on by default. If true a value in the `Request-Id` header in the request
8 | # will be used as the request ID for the rest of the request. If false
9 | # those values are ignored.
10 | trust_request_header: true
11 |
12 | # The header which the bundle will set the request ID to on
13 | # the response
14 | response_header: X-Request-Id
15 |
16 | # The service key of an object that implements
17 | # Chrisguitarguy\RequestId\RequestIdStorage
18 | # optional, defaults to `SimpleIdStorage`
19 | storage_service: ~
20 |
21 | # The service key of an object that implements
22 | # Chrisguitarguy\RequestId\RequestIdGenerator
23 | # optional, defaults to a UUID v4 based generator
24 | generator_service: ~
25 |
26 | # Whether or not to add the monolog process (see below), defaults to true
27 | enable_monolog: true
28 |
29 | # Whether or not to add the twig extension (see below), defaults to true
30 | enable_twig: true
31 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/events/listing.graphql:
--------------------------------------------------------------------------------
1 | query EventsListing(
2 | $site: [String],
3 | $eventType: [QueryArgument],
4 | $category: [QueryArgument],
5 | $tag: [QueryArgument],
6 | $start: [QueryArgument],
7 | $end: [QueryArgument],
8 | $limit: Int,
9 | $offset: Int) {
10 | total: entryCount(
11 | section: "events",
12 | site: $site,
13 | eventType: $eventType,
14 | blogCategories: $category,
15 | blogTags: $tag,
16 | startDatetime: $start,
17 | endDatetime: $end)
18 | entries(
19 | section: "events",
20 | site: $site,
21 | eventType: $eventType,
22 | blogCategories: $category,
23 | blogTags: $tag,
24 | startDatetime: $start,
25 | endDatetime: $end,
26 | limit: $limit,
27 | offset: $offset,
28 | orderBy: "startDatetime asc") {
29 | ... on events_default_Entry {
30 | ...listingEvent
31 | }
32 | ... on external_Entry {
33 | ...listingExternalEvent
34 | }
35 | ... on entryContentIsACraftPage_Entry {
36 | ...listingPageEvent
37 | }
38 | }
39 | }
40 |
41 | fragment thumbnailImage on AssetInterface {
42 | url(transform: "size360x270")
43 | srcset(sizes: ["580w"])
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/events/filters.graphql:
--------------------------------------------------------------------------------
1 | query EventFilters($site: [String]) {
2 | categories(site: $site, group: "blogCategories", orderBy: "title asc") {
3 | title
4 | slug
5 | }
6 | types: categories(site: $site, group: "eventType", orderBy: "title asc") {
7 | id
8 | title
9 | slug
10 | ... on eventType_Category {
11 | pageLead
12 | }
13 | }
14 | first: entry(section: "events", site: $site, orderBy: "startDatetime asc") {
15 | ... on events_default_Entry {
16 | year: startDatetime@formatDateTime(format: "Y")
17 | }
18 | ... on external_Entry {
19 | year: startDatetime@formatDateTime(format: "Y")
20 | }
21 | ... on entryContentIsACraftPage_Entry {
22 | year: startDatetime@formatDateTime(format: "Y")
23 | }
24 | }
25 | last: entry(section: "events", site: $site, orderBy: "startDatetime desc") {
26 | ... on events_default_Entry {
27 | year: startDatetime@formatDateTime(format: "Y")
28 | }
29 | ... on external_Entry {
30 | year: startDatetime@formatDateTime(format: "Y")
31 | }
32 | ... on entryContentIsACraftPage_Entry {
33 | year: startDatetime@formatDateTime(format: "Y")
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/News/Listing.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/news/listing.graphql')
32 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
34 | ->setRootPropertyPath('[entry]')
35 | ->addVariable('site', $siteHandle)
36 | ->cache($cacheLifetime)
37 | ->cacheTags(['newsArticles'])
38 | ;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Taxonomies/CategoryInfo.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/taxonomies/category-info.graphql')
34 | ->addVariable('site', $siteHandle)
35 | ->addVariable('handle', $handle)
36 | ->addVariable('slug', $slug)
37 | ->setRootPropertyPath('[category]')
38 | ->cache($cacheLifetime)
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Events/Page.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/events/page.graphql')
32 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
34 | ->setRootPropertyPath('[entry]')
35 |
36 | ->addVariable('site', $siteHandle)
37 | ->cache($cacheLifetime)
38 | ->cacheTags(['events'])
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/translations/messages+intl-icu.zh-hans.yaml:
--------------------------------------------------------------------------------
1 | api_available:
2 | w3c: >-
3 | W3C API 可用性: {available, select,
4 | 1 {可用}
5 | other {不可用}
6 | }
7 | craft: >-
8 | Craft CMS API 可用性: {available, select,
9 | 1 {可用}
10 | other {不可用}
11 | }
12 | specifications_found: >-
13 | 在 W3C API ({cache, select,
14 | 1 {缓存}
15 | other {实时请求}
16 | }中{total, plural,
17 | =0 {没有找到规范}
18 | one {找到 # 条规范}
19 | other {找到 # 条规范}
20 | })
21 | blog:
22 | comments:
23 | form:
24 | comment:
25 | label: 评论
26 | help: 您的邮箱地址将不会被公开。
27 | name:
28 | label: 姓名
29 | email:
30 | label: 邮箱地址
31 | submit: 发布评论
32 | cancel: 取消
33 | success: 您的评论已成功保存,将在审核之后进入他人可见状态。返回评论区
34 | components:
35 | groups_list:
36 | title: 活跃组
37 | events:
38 | archive:
39 | title: W3C archived events
40 | browse: Browse archives
41 | label: Event archive
42 | error404:
43 | title: 页面丢失
44 | message: 很抱歉,您试图访问的页面并不存在。您可以参考下面的步骤来寻找您访问的页面:
- 如果您是手动输入的 URL 网址,请您确认一下网址是否正确。
- 如果您在寻找某一特定主题的信息,请在W3C 主页上开始检索。
- 请尝试用本页面顶端的搜索图标来搜寻网站。
45 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/PressReleases/Listing.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/press-releases/listing.graphql')
31 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
32 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
33 | ->setRootPropertyPath('[entry]')
34 | ->addVariable('site', $siteHandle)
35 | ->cache($cacheLifetime)
36 | ->cacheTags(['pressReleases'])
37 | ;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/Query/W3C/Ecosystem/Evangelists.php:
--------------------------------------------------------------------------------
1 | setUri('/ecosystems/' . $slug . '/evangelists')
18 | ->addParam('items', $perPage)
19 | ->addParam('embed', true)
20 | ->addParam('page', $page)
21 | ->setRootPropertyPath('[_embedded][evangelists]')
22 | ->setCurrentPage('[page]')
23 | ->setTotalResults('[total]')
24 | ->setResultsPerPage('[limit]');
25 | // ->disableCache();
26 | ;
27 | }
28 |
29 | public function getRequiredDataProviderClass(): string
30 | {
31 | return W3C::class;
32 | }
33 |
34 | public function getMapping(): MappingStrategyInterface|array
35 | {
36 | return [
37 | '[name]' => '[name]',
38 | '[work_title]' => '[work-title]',
39 | '[phone]' => '[phone]',
40 | '[email]' => '[email]',
41 | ];
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/ecosystems/ecosystem.graphql:
--------------------------------------------------------------------------------
1 | query Ecosystem($slug: [String], $site: [String]) {
2 | entry(slug: $slug, section: "ecosystems", site: $site) {
3 | id
4 | status
5 | slug
6 | uri
7 | language
8 | title
9 | localized {
10 | title
11 | language_code: language
12 | slug
13 | }
14 | postDate
15 | dateUpdated
16 | expiryDate
17 | breadcrumbs: parent {
18 | ...breadcrumbs
19 | }
20 | ... on default_Entry {
21 | ecosystem {
22 | slug
23 | id
24 | }
25 | pageLead
26 | heroIllustration {
27 | url
28 | mimeType
29 | height
30 | width
31 | size
32 | }
33 | excerpt
34 | thumbnailImage {
35 | ...thumbnailImage
36 | }
37 | thumbnailAltText
38 | ecosystemsFlexibleComponents {
39 | ...ecosystemsFlexibleComponents
40 | }
41 | ecosystemsBottomFlexibleComponents {
42 | ...ecosystemsBottomFlexibleComponents
43 | }
44 | recentActivitiesComponentTitle
45 | recentActivitiesComponentIntroduction
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Blog/Listing.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/blog/listing.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
34 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
35 | ->setRootPropertyPath('[entry]')
36 | ->addVariable('site', $siteHandle)
37 | ->cache($cacheLifetime)
38 | ->cacheTags(['blogPosts'])
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Staff/AlumniListing.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/staff/alumni.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
34 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
35 | ->setRootPropertyPath('[entries]')
36 | ->setTotalResults('[total]')
37 |
38 | ->addVariable('site', $siteHandle)
39 | ->cache($cacheLifetime)
40 | ->cacheTags(['alumniListing'])
41 | ;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Newsletters/Listing.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/newsletters/listing.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/breadcrumbs.graphql')
34 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
35 | ->setRootPropertyPath('[entry]')
36 | ->addVariable('site', $siteHandle)
37 | ->cache($cacheLifetime)
38 | ->cacheTags(['newsletter'])
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], null, true)) {
24 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env);
25 | }
26 |
27 | if ($input->hasParameterOption('--no-debug', true)) {
28 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0');
29 | }
30 |
31 | (new Dotenv())->bootEnv(dirname(__DIR__).'/.env');
32 |
33 | if ($_SERVER['APP_DEBUG']) {
34 | umask(0000);
35 |
36 | if (class_exists(Debug::class)) {
37 | Debug::enable();
38 | }
39 | }
40 |
41 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);
42 | $application = new Application($kernel);
43 | $application->run($input);
44 |
--------------------------------------------------------------------------------
/translations/messages+intl-icu.ja.yaml:
--------------------------------------------------------------------------------
1 | api_available:
2 | w3c: >-
3 | 利用可能なW3C API: {available, select,
4 | 1 {はい}
5 | other {いいえ}
6 | }
7 | craft: >-
8 | 利用可能なCraft CMS API: {available, select,
9 | 1 {はい}
10 | other {いいえ}
11 | }
12 | specifications_found: >-
13 | W3C API({cache, select,
14 | 1 {キャッシュ}
15 | other {ライブリクエスト}
16 | } 内で {total, plural,
17 | =0 {仕様は見つかりませんでした}
18 | one {仕様 # 件が見つかりました}
19 | other {仕様 # 件が見つかりました}
20 | })
21 | blog:
22 | comments:
23 | form:
24 | comment:
25 | label: コメント
26 | help: あなたのメールアドレスは公開されません。
27 | name:
28 | label: 名前
29 | email:
30 | label: メールアドレス
31 | submit: コメントを投稿
32 | cancel: キャンセル
33 | success: あなたのコメントは正常に保存され、表示される前にモデレーションされます。 コメントに戻る
34 | components:
35 | groups_list:
36 | title: アクティブなグループ
37 | events:
38 | archive:
39 | title: W3C アーカイブ済みイベント
40 | browse: アーカイブを閲覧
41 | label: イベントアーカイブ
42 | error404:
43 | title: ページが見つかりません
44 | message: 申し訳ありませんが、アクセスしようとしていたページは存在しません。以下は、お探しのページを見つけるために試すことができるいくつかの手順です:
- URLを手動で入力した場合は、正確であることを確認してください。
- 特定のトピックの情報を探している場合は、W3Cホームページから始めてください。
- このページの上部にある検索アイコンを使用してサイトを検索してみてください。
45 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/global-navigation.graphql:
--------------------------------------------------------------------------------
1 | query GlobalNavigation ($site: [String], $limit: Int) {
2 | total: entryCount(section: "mainNavigation", type: "topLevelItem", site: $site, limit: $limit)
3 | entries(section: "mainNavigation", type: "topLevelItem", site: $site, limit: $limit) {
4 | title
5 | ... on topLevelItem_Entry {
6 | isTitleLinkInternal: mainNavigationInternalOrExternalLink
7 | titleInternalLink: internalLink {
8 | sectionHandle
9 | uri
10 | slug
11 | year: postDate@formatDateTime(format: "Y")
12 | }
13 | titleExternalLink: urlLink
14 | introText: mainNavigationDropdownIntroduction
15 | introLinks: mainNavigationIntroductionLinks {
16 | url: link
17 | title: titleLabel
18 | }
19 | children {
20 | title
21 | ... on externalLink_Entry {
22 | url: urlLink
23 | startNewColumn
24 | }
25 | ... on internalLink_Entry {
26 | startNewColumn
27 | internalLink {
28 | sectionHandle
29 | uri
30 | slug
31 | year: postDate@formatDateTime(format: "Y")
32 | }
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/docs/git_workflow.md:
--------------------------------------------------------------------------------
1 | # Git workflow
2 |
3 | The branch called `main` is the production branch, i.e. it always corresponds to the live website CMS.
4 |
5 | You should always perform development work in another branch and merge your working branch into `main` when ready. To do so,
6 | you will need to issue a pull request. The pull request will require approval by another developer and passing [continuous integration](continuous_integration.md) tests before merging.
7 |
8 | ## Naming branches
9 |
10 | Here are our recommendations for naming branches **in the context of this project**.
11 |
12 | If you are working on a new feature, please name your branch `feature/`, e.g. `feature/super-custom-field-module`
13 |
14 | If several developers are working on various features are the same time, and their work is interdependent, it is worth creating a `develop` branch from which to work. You should work directly in develop
15 | or merge your working branches in `develop` frequently.
16 |
17 | If several developers are working on various features at the same time, and in theory their work should be independent but tested and released at the same time, it is worth creating a 'release'
18 | branch in which to merge all the working branches for testing and release. Please name release branches `release/`, e.g. `release/january-website-upgrade`.
19 |
20 | If you are working on an urgent fix to the production site, please create a 'hotfix' branch from 'main', named `hotfix/`, e.g. `hotfix/component-x-failure`.
21 |
--------------------------------------------------------------------------------
/.github/workflows/php.yml:
--------------------------------------------------------------------------------
1 | name: PHP tests
2 |
3 | on:
4 | push:
5 | branches: [ main ]
6 | pull_request:
7 | branches: [ main ]
8 |
9 | jobs:
10 | build:
11 |
12 | strategy:
13 | matrix:
14 | php-versions: ['8.2']
15 |
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 |
22 | # https://github.com/marketplace/actions/setup-php-action
23 | - name: Setup PHP
24 | uses: shivammathur/setup-php@v2
25 | with:
26 | php-version: ${{ matrix.php-versions }}
27 | extensions: mbstring, intl
28 | ini-values: post_max_size=256M, max_execution_time=180
29 | tools: composer
30 |
31 | - uses: actions/checkout@v2
32 |
33 | - name: Check PHP version
34 | run: php -v
35 |
36 | - name: Install dependencies
37 | run: composer install --prefer-dist
38 |
39 | - name: Code lint PHP files
40 | run: ./vendor/bin/phplint
41 |
42 | - name: Coding standards
43 | run: ./vendor/bin/phpcs
44 |
45 | # - name: PHPUnit
46 | # run: ./vendor/phpunit/phpunit/phpunit
47 | # env:
48 | # CRAFTCMS_API_READ_TOKEN: ${{ secrets.CRAFTCMS_API_READ_TOKEN }}
49 | # CRAFTCMS_API_PUBLISH_TOKEN: ${{ secrets.CRAFTCMS_API_PUBLISH_TOKEN }}
50 | # CACHE_ENABLE: 0
51 |
52 | - name: Redirects
53 | run: php ./tests/urls/test-urls.php
54 |
55 | - name: Symfony lint service container
56 | run: php ./bin/console lint:container
57 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/Feeds/Events.php:
--------------------------------------------------------------------------------
1 | setGraphQLFromFile(__DIR__ . '/../graphql/feeds/events.graphql')
29 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/listingEvent.graphql')
30 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/listingPageEvent.graphql')
31 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/listingExternalEvent.graphql')
32 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/defaultFlexibleComponents.graphql')
33 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/thumbnailImage.graphql')
34 | ->addFragmentFromFile(__DIR__ . '/../graphql/fragments/contentImage.graphql')
35 | ->setRootPropertyPath('[entries]')
36 | ->addVariable('site', $siteHandle)
37 | ->addVariable('limit', $limit)
38 | ->cacheTags(['events'])
39 | ;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/feeds/blog.graphql:
--------------------------------------------------------------------------------
1 | query blog($site: [String], $category: [QueryArgument], $tag: [QueryArgument], $limit: Int) {
2 | entries(section: "blogPosts", site: $site, blogCategories: $category, blogTags: $tag, limit: $limit, orderBy: "postDate desc") {
3 | typeHandle
4 | id
5 | slug
6 | uri
7 | title
8 | year: postDate@formatDateTime(format: "Y")
9 | date: postDate
10 | dateUpdated
11 | ... on blogPosts_default_Entry {
12 | authors: blogAuthors {
13 | ... on author_Entry {
14 | name: authorName
15 | email: authorEmailAddress
16 | }
17 | }
18 | excerpt
19 | defaultFlexibleComponents(orderBy: "sortOrder") {
20 | ...defaultFlexibleComponents
21 | }
22 | categories: blogCategories {
23 | slug
24 | title
25 | }
26 | }
27 | ... on blogPosts_importedEntries_Entry {
28 | authors: blogAuthors {
29 | ... on author_Entry {
30 | name: authorName
31 | email: authorEmailAddress
32 | }
33 | }
34 | excerpt
35 | pageContent
36 | categories: blogCategories {
37 | slug
38 | title
39 | }
40 | }
41 | }
42 | }
43 |
44 | fragment contentImage on AssetInterface {
45 | src: url(width: 580)
46 | extension
47 | }
48 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/ecosystems/recent-activities.graphql:
--------------------------------------------------------------------------------
1 | query RecentActivities($site: [String], $ecosystemId: [QueryArgument], $endDatetime: [QueryArgument]) {
2 | recentEntries: entries(site: $site, section: ["blogPosts", "newsArticles", "pressReleases"], ecosystems: $ecosystemId, limit: 4, orderBy: "postDate DESC") {
3 | id
4 | slug
5 | sectionHandle
6 | typeHandle
7 | title
8 | uri
9 | url
10 | year: postDate @formatDateTime(format: "Y")
11 | ... on blogPosts_default_Entry {
12 | excerpt
13 | thumbnailImage {
14 | ...thumbnailImage
15 | }
16 | thumbnailAltText
17 | }
18 | ... on newsArticles_default_Entry {
19 | excerpt
20 | thumbnailImage {
21 | ...thumbnailImage
22 | }
23 | thumbnailAltText
24 | }
25 | ... on pressReleases_default_Entry {
26 | excerpt
27 | thumbnailImage {
28 | ...thumbnailImage
29 | }
30 | thumbnailAltText
31 | }
32 | }
33 | recentEvents: entries(section: "events", ecosystems: $ecosystemId, endDatetime: $endDatetime, limit: 4, orderBy: "endDatetime ASC") {
34 | ... on events_default_Entry {
35 | ...listingEvent
36 | }
37 | ... on external_Entry {
38 | ...listingExternalEvent
39 | }
40 | ... on entryContentIsACraftPage_Entry {
41 | ...listingPageEvent
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/Kernel.php:
--------------------------------------------------------------------------------
1 | import('../config/{packages}/*.yaml');
17 | $container->import('../config/{packages}/' . $this->environment . '/*.yaml');
18 |
19 | if (is_file(\dirname(__DIR__) . '/config/services.yaml')) {
20 | $container->import('../config/services.yaml');
21 | $container->import('../config/{services}_' . $this->environment . '.yaml');
22 | } elseif (is_file($path = \dirname(__DIR__) . '/config/services.php')) {
23 | (require $path)($container->withPath($path), $this);
24 | }
25 | }
26 |
27 | protected function configureRoutes(RoutingConfigurator $routes): void
28 | {
29 | $routes->import('../config/{routes}/' . $this->environment . '/*.yaml');
30 | $routes->import('../config/{routes}/*.yaml');
31 |
32 | if (is_file(\dirname(__DIR__) . '/config/routes.yaml')) {
33 | $routes->import('../config/routes.yaml');
34 | } elseif (is_file($path = \dirname(__DIR__) . '/config/routes.php')) {
35 | (require $path)($routes->withPath($path), $this);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/urls/test-urls.php:
--------------------------------------------------------------------------------
1 | 0,
32 | ]);
33 | $responses = [];
34 | $found = [];
35 |
36 | echo sprintf("Testing %s URLs to see whether they are already setup as 301 redirects\n", count($urls));
37 |
38 | foreach ($urls as $url) {
39 | $responses[] = $client->request('GET', $url);
40 | }
41 |
42 | /** @var ResponseInterface $response */
43 | foreach ($responses as $response) {
44 | echo $response->getInfo('url') . ' ' . $response->getStatusCode() . PHP_EOL;
45 |
46 | if ($response->getStatusCode() === $statusCode) {
47 | $found[] = $response->getInfo('url');
48 | }
49 | }
50 |
51 | echo PHP_EOL;
52 | echo sprintf("Found %s URLs that match %s:\n%s", count($found), $statusCode, implode(PHP_EOL, $found));
53 |
--------------------------------------------------------------------------------
/docs/continuous_integration.md:
--------------------------------------------------------------------------------
1 | # Continuous integration
2 |
3 | We use [GitHub actions](https://docs.github.com/en/actions) to run automated actions on any merge into the default branch (main).
4 |
5 | When your work includes writing some PHP, make sure to run these tests manually; at least before merging you working branch into 'main'.
6 |
7 | ## PHP
8 | Config: .github/workflows/php.yml
9 |
10 | Tests the project across different versions of PHP. The workflow runs:
11 |
12 | * [PHP linting](https://github.com/studio24/project-base-template/blob/main/docs/continuous-integration.md#php-linting) - is the code syntax valid?
13 | * [Code formatting](https://github.com/studio24/project-base-template/blob/main/docs/continuous-integration.md#code-formatting) - does the PHP code meet our coding standards?
14 |
15 | ### PHPUnit
16 |
17 | You can run PHPUnit by using the command: `./bin/phpunit tests/`
18 |
19 | ### PHP linting
20 | PHPLint tests PHP files for syntax errors.
21 |
22 | Config: .phplint.yml
23 |
24 | We exclude the vendor folder and test all other PHP files in the project.
25 |
26 | You can run Phplint manually by using the command `vendor/bin/phplint`
27 |
28 | ### Code formatting
29 | PHP_CodeSniffer (PHPCS) tests PHP files to ensure they meet coding standards.
30 |
31 | Config: .phpcs.xml.dist
32 |
33 | Coding standard enforced:
34 |
35 | * PSR-12
36 |
37 | You can run PHPCS manually by using the command `vendor/bin/phpcs`
38 |
39 | ### Fixing code issues automatically
40 | Use PHP Code Beautifier and Fixer (phpcbf) to automatically fix code issues.
41 |
42 | Run it manually by using the command `vendor/bin/phpcbf`
--------------------------------------------------------------------------------
/templates/rss_entry.html.twig:
--------------------------------------------------------------------------------
1 | {% for component in components %}
2 | {% if component.typeHandle == 'textComponent' %}
3 | {% embed '@W3CWebsiteTemplates/components/text.html.twig' %}
4 | {% block text %}
5 | {{ component.contentField|raw }}
6 | {% endblock %}
7 | {% endembed %}
8 | {% elseif component.typeHandle == 'blockquoteComponent' %}
9 | {% embed '@W3CWebsiteTemplates/components/quote.html.twig' with {'author': component.citation} %}
10 | {% block text %}
11 | {{ component.quoteText }}
12 | {% endblock %}
13 | {% endembed %}
14 | {% elseif component.typeHandle == 'imageMediaComponent' %}
15 | {% embed '@W3CWebsiteTemplates/components/image.html.twig' with {
16 | 'attr': component.imageMedia[0],
17 | 'alt': component.altText,
18 | 'caption': component.figureCaption is defined ? component.figureCaption : null,
19 | 'informative_or_decorative': component.informativeOrDecorative
20 | } %}
21 | {% endembed %}
22 | {% elseif component.typeHandle == 'videoMediaComponent' %}
23 | {% embed '@W3CWebsiteTemplates/components/video.html.twig' with {
24 | 'iframe': component.videoUrl.code,
25 | 'title': component.videoTitle,
26 | 'caption': component.videoCaption is defined ? component.videoCaption : null,
27 | 'transcript': component.linkToVideoTranscript is defined ? component.linkToVideoTranscript : null
28 | } %}
29 | {% endembed %}
30 | {% endif %}
31 | {% endfor %}
32 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/ecosystemsBottomFlexibleComponents.graphql:
--------------------------------------------------------------------------------
1 | fragment ecosystemsBottomFlexibleComponents on ecosystemsBottomFlexibleComponents_MatrixField {
2 | ... on textComponent_Entry {
3 | typeHandle
4 | contentField
5 | }
6 | ... on blockquoteComponent_Entry {
7 | typeHandle
8 | quoteText
9 | citation
10 | }
11 | ... on fiftyFiftyComponent_Entry {
12 | typeHandle
13 | showImageBeforeText
14 | image {
15 | ...contentImage
16 | }
17 | informativeOrDecorative
18 | altText
19 | titleField
20 | mainContent
21 | ctaUrl
22 | ctaCopy
23 | secondaryLinkUrl
24 | }
25 | ... on imageMediaComponent_Entry {
26 | typeHandle
27 | imageMedia {
28 | ...contentImage
29 | }
30 | altText
31 | figureCaption
32 | informativeOrDecorative
33 | }
34 | ... on videoMediaComponent_Entry {
35 | typeHandle
36 | videoTitle
37 | videoUrl {
38 | url
39 | image
40 | imageWidth
41 | imageHeight
42 | code
43 | width
44 | height
45 | aspectRatio
46 | providerName
47 | }
48 | videoCaption
49 | linkToVideoTranscript
50 | }
51 | ... on groupsListingComponent_Entry {
52 | typeHandle
53 | introduction
54 | }
55 | ... on featuredEvangelistsComponent_Entry {
56 | typeHandle
57 | title: evangelistsTitle
58 | introduction
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/Query/CraftCMS/graphql/fragments/ecosystemsFlexibleComponents.graphql:
--------------------------------------------------------------------------------
1 | fragment ecosystemsFlexibleComponents on ecosystemsFlexibleComponents_MatrixField {
2 | ... on textComponent_Entry {
3 | typeHandle
4 | contentField
5 | }
6 | ... on blockquoteComponent_Entry {
7 | typeHandle
8 | quoteText
9 | citation
10 | }
11 | ... on fiftyFiftyComponent_Entry {
12 | typeHandle
13 | showImageBeforeText
14 | image {
15 | ...contentImage
16 | }
17 | informativeOrDecorative
18 | altText
19 | titleField
20 | mainContent
21 | ctaUrl
22 | ctaCopy
23 | secondaryLinkUrl
24 | secondaryLinkCopy
25 | }
26 | ... on imageMediaComponent_Entry {
27 | typeHandle
28 | imageMedia {
29 | ...contentImage
30 | }
31 | altText
32 | figureCaption
33 | informativeOrDecorative
34 | }
35 | ... on videoMediaComponent_Entry {
36 | typeHandle
37 | videoTitle
38 | videoUrl {
39 | url
40 | image
41 | imageWidth
42 | imageHeight
43 | code
44 | width
45 | height
46 | aspectRatio
47 | providerName
48 | }
49 | videoCaption
50 | linkToVideoTranscript
51 | }
52 | ... on groupsListingComponent_Entry {
53 | typeHandle
54 | introduction
55 | }
56 | ... on featuredEvangelistsComponent_Entry {
57 | typeHandle
58 | title: evangelistsTitle
59 | introduction
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/templates/debug/test.html.twig:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | W3C test page
7 |
8 | {% block stylesheets %}{% endblock %}
9 | {% block javascripts %}{% endblock %}
10 |
11 |
12 |
13 | W3C test page
14 |
15 | Example page with default page content outputted to a basic HTML template. Once this works, integrate me with the real templates!
16 |
17 | Global navigation
18 |
19 | Is navigation cached? {% if navigation_cached %}Yes{% else %}No{% endif %}
20 |
21 |
44 |
45 | Page: {{ page.title }}
46 |
47 | Is page cached? {% if page_cached %}Yes{% else %}No{% endif %}
48 |
49 | W3C API available? {% if w3c_available %}Yes{% else %}No{% endif %}
50 |
51 |
52 |