Remove sculpin and replace with something simpler.

This commit is contained in:
Jonathan H. Wage
2018-08-23 02:13:21 +01:00
parent 97099ab3c1
commit 1f6a94c256
569 changed files with 4640 additions and 30568 deletions

21
.gitignore vendored
View File

@@ -1,13 +1,12 @@
vendor
source/projects/doctrine-*
source/api
output_*
app/config/local.yml
tests/Doctrine/Website/Tests/Docs/resources/projects
tests/Doctrine/Website/Tests/Docs/resources/docs
tests/Doctrine/Website/Tests/Docs/resources/sculpin-source
/config/local.yml
/vendor
/source/projects/doctrine-*
/source/projects/doctrine1
/source/api
/tests/Doctrine/Website/Tests/Docs/resources/projects
/tests/Doctrine/Website/Tests/Docs/resources/docs
/tests/Doctrine/Website/Tests/Docs/resources/sculpin-source
/docs
projects
build-*
/.phpcs-cache
/build-*
/projects

View File

@@ -18,26 +18,37 @@ install:
- rm composer.lock
- travis_retry composer update -n --prefer-dist
script:
- cp app/config/local.yml.dist app/config/local.yml
- ./vendor/bin/sculpin build-docs --sync-git
- ./vendor/bin/sculpin build-website
- ./vendor/bin/phpunit --debug
jobs:
include:
- stage: Coverage
- stage: Test
env: DEPENDENCIES=low
install:
- rm composer.lock
- travis_retry composer update --prefer-dist --prefer-lowest
script:
- cp config/local.yml.dist config/local.yml
- ./vendor/bin/phpunit
- stage: Test
env: COVERAGE
before_script:
- mv ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini{.disabled,}
- if [[ ! $(php -m | grep -si xdebug) ]]; then echo "xdebug required for coverage"; exit 1; fi
script:
- cp config/local.yml.dist config/local.yml
- ./bin/console build-docs --sync-git
- ./bin/console build-website
- ./vendor/bin/phpunit --coverage-clover clover.xml
after_script:
- wget https://scrutinizer-ci.com/ocular.phar
- php ocular.phar code-coverage:upload --format=php-clover clover.xml
- stage: Coding standard
install:
- travis_retry composer install -n --prefer-dist
script:
- ./vendor/bin/phpcs
- stage: Code Quality
env: CODING_STANDARDS
install: travis_retry composer install --prefer-dist
script: ./vendor/bin/phpcs
- stage: Code Quality
env: STATIC_ANALYSIS
install: travis_retry composer install --prefer-dist
script: vendor/bin/phpstan analyse

View File

@@ -1,16 +0,0 @@
<?php
declare(strict_types=1);
use Sculpin\Bundle\SculpinBundle\HttpKernel\AbstractKernel;
class SculpinKernel extends AbstractKernel
{
/**
* @return string[]
*/
protected function getAdditionalSculpinBundles() : array
{
return ['Doctrine\Website\DoctrineSculpinBundle\DoctrineSculpinBundle'];
}
}

View File

@@ -1,3 +0,0 @@
parameters:
doctrine.search.algolia.admin_api_key: 'abcd'
doctrine.projects_path: '%kernel.root_dir%/../projects'

View File

@@ -1,142 +0,0 @@
imports:
- { resource: local.yml }
- { resource: projects.yml }
- { resource: team_members.yml }
sculpin_content_types:
posts:
type: path
path: _posts
permalink: :year/:month/:day/:filename/
taxonomies:
- tags
- categories
sculpin_twig:
source_view_paths: ['_views', '_layouts', '_partials', '_includes']
extensions: ['', 'twig', 'html', 'html.twig', 'twig.html', 'rst']
services:
doctrine.twig.main.extension:
class: Doctrine\Website\Twig\MainExtension
public: false
arguments:
- '%doctrine.team_members%'
tags:
- { name: twig.extension }
doctrine.twig.project.extension:
class: Doctrine\Website\Twig\ProjectExtension
public: false
arguments:
- '@doctrine.project.repository'
- '%doctrine.sculpin_source_path%'
tags:
- { name: twig.extension }
doctrine.project.factory:
class: Doctrine\Website\Projects\ProjectFactory
public: false
doctrine.process.factory:
class: Doctrine\Website\ProcessFactory
public: false
doctrine.project.repository:
class: Doctrine\Website\Projects\ProjectRepository
public: false
arguments:
- '%doctrine.projects%'
- '@doctrine.project.factory'
doctrine.project.git_syncer:
class: Doctrine\Website\Projects\ProjectGitSyncer
public: false
arguments:
- '@doctrine.process.factory'
- '%doctrine.projects_path%'
doctrine.search.algolia_client:
class: AlgoliaSearch\Client
public: false
arguments:
- '%doctrine.search.algolia.application_id%'
- '%doctrine.search.algolia.admin_api_key%'
doctrine.search.indexer:
class: Doctrine\Website\Docs\SearchIndexer
public: false
arguments:
- '@doctrine.search.algolia_client'
- '@doctrine.docs.rst_builder'
doctrine.rst.kernel.html:
class: Doctrine\RST\HTML\Kernel
public: false
doctrine.rst.kernel:
class: Doctrine\Website\RST\Kernel
public: false
arguments:
- @doctrine.rst.kernel.html
- []
doctrine.rst.builder:
class: Doctrine\RST\Builder
public: false
arguments:
- '@doctrine.rst.kernel'
doctrine.docs.api_builder:
class: Doctrine\Website\Docs\APIBuilder
public: false
arguments:
- '@doctrine.process.factory'
- '%doctrine.projects_path%'
- '%doctrine.sculpin_source_path%'
doctrine.docs.rst_builder:
class: Doctrine\Website\Docs\RSTBuilder
arguments:
- '%doctrine.sculpin_source_path%'
- '@doctrine.rst.builder'
- '%doctrine.projects_path%'
doctrine.docs.build_docs:
class: Doctrine\Website\Docs\BuildDocs
public: true
arguments:
- '@doctrine.project.repository'
- '@doctrine.project.git_syncer'
- '@doctrine.docs.api_builder'
- '@doctrine.docs.rst_builder'
- '@doctrine.search.indexer'
doctrine.website_builder:
class: Doctrine\Website\WebsiteBuilder
public: true
arguments:
- '@doctrine.process.factory'
- '@sculpin.site_configuration'
- '@doctrine.project.repository'
- '%kernel.root_dir%'
doctrine.watcher:
class: Doctrine\Website\Watcher
public: true
arguments:
- '@doctrine.process.factory'
- '%kernel.root_dir%'
doctrine.deployer:
class: Doctrine\Website\Deployer
public: true
arguments:
- '@doctrine.process.factory'
- '%kernel.environment%'
parameters:
doctrine.sculpin_source_path: '%kernel.root_dir%/../source'
doctrine.search.algolia.application_id: YVYTFT9XMW
doctrine.search.algolia.index: pages

View File

@@ -1,12 +0,0 @@
# The contents of this file are parsed and made available as
# via `site.*`. So for example, {{ site.title }} can be used
# in a template to get the contents of the `title` key.
title: Doctrine
subtitle: PHP Database Tools
url: http://lcl.doctrine-project.org:8080
keywords: [php, mysql, orm, dbal, database, mongodb, odm, annotations, migrations, cache, couchdb]
description: >
The Doctrine Project is the home to several PHP libraries primarily
focused on database storage and object mapping. The core projects
are the Object Relational Mapper (ORM) and the Database Abstraction
Layer (DBAL) it is built upon.

View File

@@ -1,5 +0,0 @@
imports:
- sculpin_site.yml
url: https://www.doctrine-project.org
google_analytics_tracking_id: UA-288343-7

View File

@@ -1,4 +0,0 @@
imports:
- sculpin_site.yml
url: https://staging.doctrine-project.org

View File

@@ -1,29 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
use Sculpin\Core\Console\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class DeployCommand extends ContainerAwareCommand
{
protected function configure() : void
{
$this
->setName('deploy')
->setDescription('Deploy the Doctrine website.')
;
}
protected function execute(InputInterface $input, OutputInterface $output) : void
{
$container = $this->getContainer();
$deployer = $container->get('doctrine.deployer');
$deployer->deploy($output);
}
}

View File

@@ -1,45 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
use Sculpin\Core\Console\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use function sprintf;
class WatchCommand extends ContainerAwareCommand
{
protected function configure() : void
{
$this
->setName('watch')
->setDescription('Watch for changes to the website source code and build.')
->addArgument(
'build-dir',
InputArgument::OPTIONAL,
'The directory where the website is built'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output) : void
{
$container = $this->getContainer();
$rootDir = $container->getParameter('kernel.root_dir');
$env = $container->getParameter('kernel.environment');
$buildDir = $input->getArgument('build-dir');
if (! $buildDir) {
$buildDir = sprintf('%s/../build-%s', $rootDir, $env);
}
$watcher = $this->getContainer()->get('doctrine.watcher');
$watcher->watch($buildDir, $output);
}
}

View File

@@ -1,25 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\DependencyInjection\CompilerPass;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use function array_keys;
use function array_map;
class DirectivesCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container) : void
{
$kernel = $container->getDefinition('doctrine.rst.kernel');
$kernel->replaceArgument(
1,
array_map(
[$container, 'getDefinition'],
array_keys($container->findTaggedServiceIds('doctrine.rst.directive'))
)
);
}
}

View File

@@ -1,22 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
class DoctrineSculpinExtension extends Extension
{
/**
* @param mixed[] $config
*/
public function load(array $config, ContainerBuilder $container) : void
{
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
}

View File

@@ -1,17 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle;
use Doctrine\Website\DoctrineSculpinBundle\DependencyInjection\CompilerPass\DirectivesCompilerPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class DoctrineSculpinBundle extends Bundle
{
public function build(ContainerBuilder $container) : void
{
$container->addCompilerPass(new DirectivesCompilerPass());
}
}

View File

@@ -1,111 +0,0 @@
services:
doctrine.code_highlighter:
public: false
class: Highlight\Highlighter
doctrine.code_block.renderer:
public: false
class: Doctrine\Website\Docs\CodeBlockRenderer
arguments:
- '@doctrine.code_block.console.renderer'
- '@doctrine.code_block.with_line_numbers.renderer'
doctrine.code_block.language_detector:
public: false
class: Doctrine\Website\Docs\CodeBlockLanguageDetector
doctrine.code_block.console.renderer:
public: false
class: Doctrine\Website\Docs\CodeBlockConsoleRenderer
doctrine.code_block.with_line_numbers.renderer:
public: false
class: Doctrine\Website\Docs\CodeBlockWithLineNumbersRenderer
arguments:
- '@doctrine.code_highlighter'
doctrine.website.directive.warning:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\WarningDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.caution:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\CautionDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.tip:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TipDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.configuration_block:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\ConfigurationBlockDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.section_author:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\SectionAuthorDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.version_added:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\VersionAddedDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.role:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\RoleDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.index:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\IndexDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.hint:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\HintDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.notice:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\NoticeDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.note:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\NoteDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.toc:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TocDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.toc_header:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\TocHeaderDirective
arguments: []
tags: [{ name: doctrine.rst.directive }]
doctrine.website.directive.code_block:
public: false
class: Doctrine\Website\DoctrineSculpinBundle\Directive\CodeBlockDirective
arguments:
- '@doctrine.code_block.renderer'
- '@doctrine.code_block.language_detector'
tags: [{ name: doctrine.rst.directive }]

View File

@@ -1,100 +0,0 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website;
use Symfony\Component\Console\Output\OutputInterface;
use function array_merge;
use function file_put_contents;
use function filemtime;
use function glob;
use function is_dir;
use function realpath;
use function sprintf;
use function time;
class Watcher
{
/** @var ProcessFactory */
private $processFactory;
/** @var string */
private $kernelRootDir;
public function __construct(ProcessFactory $processFactory, string $kernelRootDir)
{
$this->processFactory = $processFactory;
$this->kernelRootDir = $kernelRootDir;
}
public function watch(string $buildDir, OutputInterface $output) : void
{
$rootDir = realpath($this->kernelRootDir . '/..');
$buildScriptPath = sprintf(
'%s/doctrine build-website %s --env=dev',
$rootDir,
$buildDir
);
$startPaths = [
$rootDir . '/app/*',
$rootDir . '/source/*',
];
$lastTime = time();
while (true) {
$files = $this->recursiveGlob($startPaths);
foreach ($files as $file) {
$time = filemtime($file);
if ($time <= $lastTime) {
continue;
}
$lastTime = time();
$output->writeln(sprintf('%s was changed. Building...', $file));
$this->processFactory->run($buildScriptPath, function ($type, $buffer) use ($output) : void {
$output->write($buffer);
});
file_put_contents($buildDir . '/changed', time());
}
}
}
/**
* @param string[] $paths
*
* @return string[]
*/
private function recursiveGlob(array $paths) : array
{
$allFiles = [];
foreach ($paths as $path) {
$files = glob($path);
$allFiles = array_merge($allFiles, $files);
foreach ($files as $file) {
if (! is_dir($file)) {
continue;
}
$dirPath = $file . '/*';
$dirFiles = $this->recursiveGlob([$dirPath]);
$allFiles = array_merge($allFiles, $dirFiles);
}
}
return $allFiles;
}
}

16
bin/console Executable file
View File

@@ -0,0 +1,16 @@
#!/usr/bin/env php
<?php
require_once __DIR__ . '/../vendor/autoload.php';
use Doctrine\Website\Application;
use Symfony\Component\Console\Input\ArgvInput;
$input = new ArgvInput();
$env = $input->getParameterOption(['--env', '-e'], 'dev');
$container = Application::getContainer($env);
$application = $container->get(Application::class);
$application->run($input);

View File

@@ -1,40 +0,0 @@
<?php
namespace ComponentManager;
use Composer\Script\Event;
use Symfony\Component\Filesystem\Filesystem;
class ComponentManager
{
public static function postComposerInstall(Event $event)
{
$config = $event->getComposer()->getConfig();
$componentDir = $config->get('component-dir');
$components = $config->get('components');
$vendorDir = $config->get('vendor-dir');
// if either configuration is empty it's a noop
if (empty($componentDir) || empty($components)) {
return;
}
$componentDir = __DIR__ .'/'. $componentDir;
if (!is_dir($componentDir)) {
mkdir($componentDir);
}
$filesystem = new Filesystem();
foreach ($components as $component) {
$componentSource = $vendorDir .'/'. $component;
if (!is_dir($componentSource)) {
continue;
}
$filesystem->mirror($componentSource, $componentDir .'/'. basename($component));
}
}
}

View File

@@ -1,9 +1,7 @@
{
"name": "doctrine/doctrine-website",
"description": "Source code for doctrine-project.org",
"type": "jwage.com",
"minimum-stability": "dev",
"prefer-stable" : true,
"type": "project",
"license": "MIT",
"authors": [
{
@@ -13,36 +11,40 @@
}
],
"require": {
"algolia/algoliasearch-client-php": "~1.25.0",
"components/highlightjs": "^9.7",
"dflydev/embedded-composer": "^1.0@dev",
"algolia/algoliasearch-client-php": "^1.27",
"doctrine/rst-parser": "dev-master",
"kriswallsmith/assetic": "1.1.2",
"scrivo/highlight.php": "9.12.0.2",
"sculpin/sculpin": "^2.1@dev"
"erusev/parsedown": "^1.7",
"scrivo/highlight.php": "v9.12.0.4",
"symfony/config": "^4.1",
"symfony/console": "^4.1",
"symfony/dependency-injection": "^4.1",
"symfony/filesystem": "^4.1",
"symfony/finder": "^4.1",
"symfony/process": "^4.1",
"symfony/yaml": "^4.1",
"twig/twig": "^2.5"
},
"require-dev": {
"phpunit/phpunit": "^7.0",
"doctrine/coding-standard": "^4.0",
"phpstan/phpstan": "^0.10",
"phpstan/phpstan-deprecation-rules": "^0.10",
"phpstan/phpstan-phpunit": "^0.10",
"phpstan/phpstan-strict-rules": "^0.10",
"phpunit/phpunit": "^7.0",
"symfony/dom-crawler": "^4.0",
"symfony/css-selector": "^4.0"
},
"config": {
"component-dir": "source/components",
"components": [
"components/highlightjs"
],
"sort-packages": true
},
"scripts": {
"post-install-cmd": [
"ComponentManager\\ComponentManager::postComposerInstall"
]
},
"autoload": {
"classmap": ["component-manager.php"],
"psr-0": {
"Doctrine": "app/src/"
"psr-4": {
"Doctrine\\Website\\": "lib/"
}
},
"autoload-dev": {
"psr-4": {
"Doctrine\\Website\\Tests\\": "tests/"
}
}
}

3389
composer.lock generated

File diff suppressed because it is too large Load Diff

17
config/config.yml Normal file
View File

@@ -0,0 +1,17 @@
parameters:
doctrine.website.algolia.app_id: 'YVYTFT9XMW'
doctrine.website.algolia.admin_api_key: '1234'
doctrine.website.projects_path: '%doctrine.website.root_dir%/projects'
doctrine.website.source_path: '%doctrine.website.root_dir%/source'
doctrine.website.templates_path: '%doctrine.website.root_dir%/templates'
doctrine.website.title: Doctrine
doctrine.website.subtitle: PHP Database Tools
doctrine.website.url: http://lcl.doctrine-project.org:8080
doctrine.website.keywords: [php, mysql, orm, dbal, database, mongodb, odm, annotations, migrations, cache, couchdb]
doctrine.website.description: >
The Doctrine Project is the home to several PHP libraries primarily
focused on database storage and object mapping. The core projects
are the Object Relational Mapper (ORM) and the Database Abstraction
Layer (DBAL) it is built upon.

4
config/config_dev.yml Normal file
View File

@@ -0,0 +1,4 @@
imports:
- config.yml
parameters: []

5
config/config_prod.yml Normal file
View File

@@ -0,0 +1,5 @@
imports:
- config.yml
parameters:
doctrine.website.url: 'https://www.doctrine-project.org'

View File

@@ -0,0 +1,5 @@
imports:
- { resource: config.yml }
parameters:
doctrine.website.url: 'https://staging.doctrine-project.org'

3
config/local.yml.dist Normal file
View File

@@ -0,0 +1,3 @@
parameters:
doctrine.website.algolia.admin_api_key: 'abcd'
doctrine.website.projects_path: '%doctrine.website.root_dir%/projects'

View File

@@ -1,5 +1,5 @@
parameters:
doctrine.projects:
doctrine.website.projects:
orm:
active: true
name: Object Relational Mapper

65
config/services.xml Normal file
View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<defaults autowire="true" autoconfigure="true" public="false">
<bind key="$rootDir">%doctrine.website.root_dir%</bind>
<bind key="$env">%doctrine.website.env%</bind>
<bind key="$projectsPath">%doctrine.website.projects_path%</bind>
<bind key="$sourcePath">%doctrine.website.source_path%</bind>
<bind key="$projects">%doctrine.website.projects%</bind>
<bind key="$teamMembers">%doctrine.website.team_members%</bind>
<bind key="$templatesPath">%doctrine.website.templates_path%</bind>
</defaults>
<prototype namespace="Doctrine\Website\" resource="../lib/*" />
<service id="Doctrine\Website\Application" autowire="true" public="true" />
<service id="Doctrine\RST\Builder">
<argument type="service" id="Doctrine\Website\RST\Kernel" />
</service>
<service id="Doctrine\RST\HTML\Kernel" autowire="true" />
<service id="Highlight\Highlighter" autowire="true" />
<service id="Parsedown" class="Parsedown" autowire="true" />
<service id="Symfony\Component\Console\Application" autowire="true" />
<service id="Symfony\Component\Filesystem\Filesystem" autowire="true" />
<service id="AlgoliaSearch\Client">
<argument>%doctrine.website.algolia.app_id%</argument>
<argument>%doctrine.website.algolia.admin_api_key%</argument>
</service>
<service id="Doctrine\Website\Site">
<argument>%doctrine.website.title%</argument>
<argument>%doctrine.website.subtitle%</argument>
<argument>%doctrine.website.url%</argument>
<argument>%doctrine.website.keywords%</argument>
<argument>%doctrine.website.description%</argument>
<argument>%doctrine.website.env%</argument>
</service>
<service id="Doctrine\Website\RST\Kernel" autowire="true" public="true">
<argument type="service" id="Doctrine\RST\HTML\Kernel" />
<argument type="collection">
<argument type="service" id="Doctrine\Website\RST\Directive\CautionDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\CodeBlockDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\ConfigurationBlockDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\HintDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\IndexDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\NoteDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\NoticeDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\RoleDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\SectionAuthorDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\TipDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\TocDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\TocHeaderDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\VersionAddedDirective" />
<argument type="service" id="Doctrine\Website\RST\Directive\WarningDirective" />
</argument>
</service>
</services>
</container>

View File

@@ -1,5 +1,5 @@
parameters:
doctrine.team_members:
doctrine.website.team_members:
# active
alcaeus:
name: Andreas

View File

@@ -1 +1 @@
vendor/bin/sculpin
bin/console

79
lib/Application.php Normal file
View File

@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website;
use Doctrine\Website\Commands\BuildDocsCommand;
use Doctrine\Website\Commands\BuildWebsiteCommand;
use Doctrine\Website\Commands\DeployCommand;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\Application as BaseApplication;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use function file_exists;
use function realpath;
use function sprintf;
class Application
{
/** @var BaseApplication */
private $application;
/** @var BuildDocsCommand */
private $buildDocsCommand;
/** @var BuildWebsiteCommand */
private $buildWebsiteCommand;
/** @var DeployCommand */
private $deployCommand;
public function __construct(
BaseApplication $application,
BuildDocsCommand $buildDocsCommand,
BuildWebsiteCommand $buildWebsiteCommand,
DeployCommand $deployCommand
) {
$this->application = $application;
$this->buildDocsCommand = $buildDocsCommand;
$this->buildWebsiteCommand = $buildWebsiteCommand;
$this->deployCommand = $deployCommand;
}
public function run(InputInterface $input) : int
{
$this->application->add($this->buildDocsCommand);
$this->application->add($this->buildWebsiteCommand);
$this->application->add($this->deployCommand);
return $this->application->run($input);
}
public static function getContainer(string $env) : ContainerBuilder
{
$container = new ContainerBuilder();
$container->setParameter('doctrine.website.env', $env);
$container->setParameter('doctrine.website.root_dir', realpath(__DIR__ . '/..'));
$container->setParameter('doctrine.website.config_dir', realpath(__DIR__ . '/../config'));
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader->load('services.xml');
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../config'));
$loader->load('projects.yml');
$loader->load('team_members.yml');
$loader->load(sprintf('config_%s.yml', $env));
if (file_exists($container->getParameter('doctrine.website.config_dir') . '/local.yml')) {
$loader->load('local.yml');
}
$container->compile();
return $container;
}
}

122
lib/Builder/SourceFile.php Normal file
View File

@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Builder;
use DateTime;
use function count;
use function explode;
use function in_array;
use function sprintf;
use function strpos;
use function strtotime;
class SourceFile
{
private const TWIG_EXTENSIONS = ['html', 'md', 'rst', 'xml', 'txt'];
private const NEEDS_LAYOUT_EXTENSIONS = ['html', 'md', 'rst'];
private const MARKDOWN_EXTENSION = 'md';
/** @var string */
private $extension;
/** @var string */
private $writePath;
/** @var string */
private $contents;
/** @var mixed[] */
private $parameters = [];
/**
* @param mixed[] $parameters
*/
public function __construct(
string $extension,
string $writePath,
string $contents,
array $parameters
) {
$this->extension = $extension;
$this->writePath = $writePath;
$this->contents = $contents;
$this->parameters = $parameters;
}
public function getWritePath() : string
{
return $this->writePath;
}
public function getUrl() : string
{
return $this->parameters['url'];
}
public function getDate() : DateTime
{
$e = explode('/', $this->getUrl());
if (count($e) < 4) {
return new DateTime();
}
$date = strtotime(sprintf('%s/%s/%s', $e[1], $e[2], $e[3]));
if ($date === false) {
return new DateTime();
}
return (new DateTime())->setTimestamp($date);
}
public function getExtension() : string
{
return $this->extension;
}
public function isMarkdown() : bool
{
return $this->getExtension() === self::MARKDOWN_EXTENSION;
}
public function isTwig() : bool
{
return in_array($this->getExtension(), self::TWIG_EXTENSIONS, true) && $this->isApiDocs() === false;
}
public function isLayoutNeeded() : bool
{
return in_array($this->getExtension(), self::NEEDS_LAYOUT_EXTENSIONS, true);
}
public function isApiDocs() : bool
{
return strpos($this->getUrl(), '/api/') === 0;
}
public function getContents() : string
{
return $this->contents;
}
/**
* @return mixed[]
*/
public function getParameters() : array
{
return $this->parameters;
}
/**
* @return mixed
*/
public function getParameter(string $key)
{
return $this->parameters[$key] ?? '';
}
}

View File

@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Builder;
use Parsedown;
use Symfony\Component\Filesystem\Filesystem;
class SourceFileBuilder
{
/** @var SourceFileRenderer */
private $sourceFileRenderer;
/** @var Filesystem */
private $filesystem;
/** @var Parsedown */
private $parsedown;
public function __construct(
SourceFileRenderer $sourceFileRenderer,
Filesystem $filesystem,
Parsedown $parsedown
) {
$this->sourceFileRenderer = $sourceFileRenderer;
$this->filesystem = $filesystem;
$this->parsedown = $parsedown;
}
public function buildFile(SourceFile $sourceFile, string $buildDir) : void
{
$rendered = $sourceFile->getContents();
if ($sourceFile->isMarkdown()) {
$rendered = $this->parsedown->text($rendered);
}
if ($sourceFile->isTwig()) {
$rendered = $this->sourceFileRenderer->render(
$sourceFile,
$rendered
);
}
$this->filesystem->dumpFile($sourceFile->getWritePath(), $rendered);
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Builder;
use Doctrine\Website\Site;
use Doctrine\Website\Twig\TwigRenderer;
use function array_merge;
use function preg_match_all;
class SourceFileRenderer
{
/** @var TwigRenderer */
private $twigRenderer;
/** @var Site */
private $site;
public function __construct(TwigRenderer $twigRenderer, Site $site)
{
$this->twigRenderer = $twigRenderer;
$this->site = $site;
}
public function render(SourceFile $sourceFile, string $contents) : string
{
$template = $this->prepareTemplate($sourceFile, $contents);
$pageParameters = $this->preparePageParameters($sourceFile);
return $this->twigRenderer->render($template, [
'page' => $pageParameters,
'site' => $this->site,
]);
}
/**
* @return mixed[]
*/
private function preparePageParameters(SourceFile $sourceFile) : array
{
return array_merge($sourceFile->getParameters(), [
'date' => $sourceFile->getDate(),
]);
}
private function prepareTemplate(SourceFile $sourceFile, string $contents) : string
{
if ($sourceFile->isLayoutNeeded()) {
if (! preg_match_all('/{%\s+block\s+(\w+)\s+%}(.*?){%\s+endblock\s+%}/si', $contents, $matches)) {
$contents = '{% block content %}' . $contents . '{% endblock %}';
}
$contents = '{% extends "layouts/' . $sourceFile->getParameter('layout') . '.html.twig" %}' . $contents;
}
return $contents;
}
}

View File

@@ -0,0 +1,126 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Builder;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Yaml\Yaml;
use function end;
use function explode;
use function file_get_contents;
use function in_array;
use function preg_match;
use function preg_replace;
use function str_replace;
use function strrpos;
use function substr;
class SourceFileRepository
{
/** @var string */
private $rootDir;
public function __construct(string $rootDir)
{
$this->rootDir = $rootDir;
}
/**
* @return SourceFile[]
*/
public function getFiles(string $buildDir, string $inPath = 'source') : array
{
$finder = new Finder();
$finder
->in($this->rootDir . '/' . $inPath)
->files();
$files = [];
foreach ($finder as $splFileInfo) {
$path = $splFileInfo->getRealPath();
$contents = file_get_contents($path);
$extension = $this->getExtension($path);
$writePath = $this->getWritePath($buildDir, $path, $extension);
$parameters = $this->getFileParameters($buildDir, $writePath, $contents);
$writePath = $buildDir . $parameters['url'];
$contents = $this->stripFileParameters($contents);
$files[] = new SourceFile(
$extension,
$writePath,
$contents,
$parameters
);
}
return $files;
}
private function getWritePath(string $buildDir, string $path, string $extension) : string
{
$writePath = $buildDir . str_replace($this->rootDir . '/source', '', $path);
if (in_array($extension, ['md', 'rst'], true)) {
$writePath = substr($writePath, 0, strrpos($writePath, '.')) . '.html';
}
return $writePath;
}
private function getExtension(string $path) : string
{
$e = explode('.', $path);
return end($e);
}
private function stripFileParameters(string $contents) : string
{
return preg_replace('/^\s*(?:---[\s]*[\r\n]+)(.*?)(?:---[\s]*[\r\n]+)(.*?)$/s', '$2', $contents);
}
/**
* @return mixed[]
*/
private function getFileParameters(string $buildDir, string $writePath, string $string) : array
{
$parameters = [];
if (preg_match('/^\s*(?:---[\s]*[\r\n]+)(.*?)(?:---[\s]*[\r\n]+)(.*?)$/s', $string, $matches)) {
if (preg_match('/^(\s*[-]+\s*|\s*)$/', $matches[1]) === 0) {
$parameters = Yaml::parse($matches[1], 1);
}
}
if (! isset($parameters['layout'])) {
$parameters['layout'] = 'default';
}
$parameters['url'] = $this->getUrl($buildDir, $writePath, $parameters);
return $parameters;
}
/**
* @param mixed[] $parameters
*/
private function getUrl(string $buildDir, string $writePath, array $parameters) : string
{
$permalink = $parameters['permalink'] ?? '';
if ($permalink !== '' && $permalink !== 'none') {
return $permalink;
}
return str_replace($buildDir, '', $writePath);
}
}

View File

@@ -2,15 +2,26 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
namespace Doctrine\Website\Commands;
use Sculpin\Core\Console\Command\ContainerAwareCommand;
use Doctrine\Website\Docs\BuildDocs;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class BuildDocsCommand extends ContainerAwareCommand
class BuildDocsCommand extends Command
{
/** @var BuildDocs */
private $buildDocs;
public function __construct(BuildDocs $buildDocs)
{
parent::__construct();
$this->buildDocs = $buildDocs;
}
protected function configure() : void
{
$this
@@ -46,6 +57,12 @@ class BuildDocsCommand extends ContainerAwareCommand
InputOption::VALUE_NONE,
'Sync git repositories before building.'
)
->addOption(
'env',
'e',
InputOption::VALUE_REQUIRED,
'The environment.'
)
;
}
@@ -57,9 +74,7 @@ class BuildDocsCommand extends ContainerAwareCommand
$buildSearchIndexes = (bool) $input->getOption('search');
$syncGit = (bool) $input->getOption('sync-git');
$buildDocs = $this->getContainer()->get('doctrine.docs.build_docs');
$buildDocs->build(
$this->buildDocs->build(
$output,
$projectToBuild,
$versionToBuild,

View File

@@ -2,23 +2,45 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Command;
namespace Doctrine\Website\Commands;
use Doctrine\Website\WebsiteBuilder;
use InvalidArgumentException;
use Sculpin\Core\Console\Command\ContainerAwareCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use function in_array;
use function ini_set;
use function is_dir;
use function mkdir;
use function realpath;
use function sprintf;
class BuildWebsiteCommand extends ContainerAwareCommand
class BuildWebsiteCommand extends Command
{
/** @var WebsiteBuilder */
private $websiteBuilder;
/** @var string */
private $rootDir;
/** @var string */
private $env;
public function __construct(
WebsiteBuilder $websiteBuilder,
string $rootDir,
string $env
) {
parent::__construct();
$this->websiteBuilder = $websiteBuilder;
$this->rootDir = $rootDir;
$this->env = $env;
}
protected function configure() : void
{
$this
@@ -35,26 +57,29 @@ class BuildWebsiteCommand extends ContainerAwareCommand
InputOption::VALUE_NONE,
'Publish the build to GitHub Pages.'
)
->addOption(
'env',
'e',
InputOption::VALUE_REQUIRED,
'The environment.'
)
;
}
protected function execute(InputInterface $input, OutputInterface $output) : void
{
$container = $this->getContainer();
ini_set('memory_limit', '1024M');
$rootDir = $container->getParameter('kernel.root_dir');
$env = $container->getParameter('kernel.environment');
$publish = (bool) $input->getOption('publish');
$publish = $input->getOption('publish');
if ($publish && ! in_array($env, WebsiteBuilder::PUBLISHABLE_ENVS)) {
throw new InvalidArgumentException(sprintf('You cannot publish the "%s" environment.', $env));
if ($publish && ! in_array($this->env, WebsiteBuilder::PUBLISHABLE_ENVS, true)) {
throw new InvalidArgumentException(sprintf('You cannot publish the "%s" environment.', $this->env));
}
$buildDir = $input->getArgument('build-dir');
if (! $buildDir) {
$buildDir = sprintf('%s/../build-%s', $rootDir, $env);
if ($buildDir === null) {
$buildDir = sprintf('%s/build-%s', $this->rootDir, $this->env);
}
if (! is_dir($buildDir)) {
@@ -63,8 +88,6 @@ class BuildWebsiteCommand extends ContainerAwareCommand
$buildDir = realpath($buildDir);
$buildWebsite = $container->get('doctrine.website_builder');
$buildWebsite->build($output, $buildDir, $env, $publish);
$this->websiteBuilder->build($output, $buildDir, $this->env, $publish);
}
}

View File

@@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Commands;
use Doctrine\Website\Deployer;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class DeployCommand extends Command
{
/** @var Deployer */
private $deployer;
public function __construct(Deployer $deployer)
{
parent::__construct();
$this->deployer = $deployer;
}
protected function configure() : void
{
$this
->setName('deploy')
->setDescription('Deploy the Doctrine website.')
->addOption(
'env',
'e',
InputOption::VALUE_REQUIRED,
'The environment.'
)
;
;
}
protected function execute(InputInterface $input, OutputInterface $output) : void
{
$this->deployer->deploy($output);
}
}

View File

@@ -37,7 +37,7 @@ class Deployer
public function deploy(OutputInterface $output) : void
{
if (! in_array($this->env, self::ENVS)) {
if (! in_array($this->env, self::ENVS, true)) {
throw new InvalidArgumentException(
sprintf('Cannot deploy the %s environment.', $this->env)
);
@@ -72,11 +72,7 @@ class Deployer
// build the docs, website and publish
$deployCommand = sprintf(
'cd /data/doctrine-website-%s && ./doctrine build-docs --api --sync-git && ./doctrine build-website /data/doctrine-website-build-%s --env=%s --publish',
$this->env,
$this->env,
$this->env,
$this->env,
'cd /data/doctrine-website-%s && ./bin/console build-docs --api --sync-git && ./bin/console build-website /data/doctrine-website-build-%s --env=%s --publish',
$this->env,
$this->env,
$this->env

View File

@@ -20,16 +20,16 @@ class APIBuilder
private $projectsPath;
/** @var string */
private $sculpinSourcePath;
private $sourcePath;
public function __construct(
ProcessFactory $processFactory,
string $projectsPath,
string $sculpinSourcePath
string $sourcePath
) {
$this->processFactory = $processFactory;
$this->projectsPath = $projectsPath;
$this->sculpinSourcePath = $sculpinSourcePath;
$this->processFactory = $processFactory;
$this->projectsPath = $projectsPath;
$this->sourcePath = $sourcePath;
}
public function buildAPIDocs(
@@ -50,7 +50,7 @@ return new Sami\Sami('%s', [
CONFIG;
$codeDir = $this->projectsPath . '/' . $project->getRepositoryName() . $project->getCodePath();
$buildDir = $this->sculpinSourcePath . '/api/' . $project->getSlug() . '/' . $version->getSlug();
$buildDir = $this->sourcePath . '/api/' . $project->getSlug() . '/' . $version->getSlug();
$cacheDir = $this->projectsPath . '/' . $project->getRepositoryName() . '/cache';
$renderedConfigContent = sprintf(
@@ -64,7 +64,7 @@ CONFIG;
);
$configPath = $this->projectsPath . '/' . $project->getRepositoryName() . '/sami.php';
$samiPharPath = $this->sculpinSourcePath . '/../sami.phar';
$samiPharPath = $this->sourcePath . '/../sami.phar';
$this->filePutContents($configPath, $renderedConfigContent);

View File

@@ -29,7 +29,7 @@ class CodeBlockRenderer
*/
public function render(array $lines, string $language) : string
{
if (in_array($language, self::CONSOLE_LANGUAGES)) {
if (in_array($language, self::CONSOLE_LANGUAGES, true)) {
return $this->codeBlockConsoleRenderer->render(
$lines
);

View File

@@ -96,7 +96,7 @@ TEMPLATE;
private function shouldHighlight(string $language) : bool
{
return $language !== '' && ! in_array($language, self::LANGUAGES_NOT_TO_HIGHLIGHT);
return $language !== '' && ! in_array($language, self::LANGUAGES_NOT_TO_HIGHLIGHT, true);
}
/**

View File

@@ -8,22 +8,26 @@ use Doctrine\RST\Builder;
use Doctrine\RST\Document;
use Doctrine\Website\Projects\Project;
use Doctrine\Website\Projects\ProjectVersion;
use function array_merge;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use function array_filter;
use function array_map;
use function array_values;
use function dirname;
use function file_exists;
use function file_get_contents;
use function file_put_contents;
use function glob;
use function is_dir;
use function iterator_to_array;
use function mkdir;
use function preg_match;
use function preg_replace;
use function shell_exec;
use function realpath;
use function sprintf;
use function str_replace;
use function strpos;
use function trim;
use function unlink;
class RSTBuilder
{
@@ -51,7 +55,7 @@ class RSTBuilder
TEMPLATE;
public const SCULPIN_TEMPLATE = <<<TEMPLATE
public const PARAMETERS_TEMPLATE = <<<TEMPLATE
---
layout: "documentation"
indexed: true
@@ -76,11 +80,14 @@ TEMPLATE;
SIDEBAR;
/** @var string */
private $sculpinSourcePath;
private $sourcePath;
/** @var Builder */
private $builder;
/** @var Filesystem */
private $filesystem;
/** @var string */
private $projectsPath;
@@ -88,14 +95,16 @@ SIDEBAR;
private $tmpPath;
public function __construct(
string $sculpinSourcePath,
string $sourcePath,
Builder $builder,
Filesystem $filesystem,
string $projectsPath
) {
$this->sculpinSourcePath = $sculpinSourcePath;
$this->builder = $builder;
$this->projectsPath = $projectsPath;
$this->tmpPath = $this->sculpinSourcePath . '/../docs';
$this->sourcePath = $sourcePath;
$this->builder = $builder;
$this->filesystem = $filesystem;
$this->projectsPath = $projectsPath;
$this->tmpPath = $this->sourcePath . '/../docs';
}
/**
@@ -125,7 +134,7 @@ SIDEBAR;
$outputPath = $this->getProjectVersionTmpPath($project, $version);
// clear tmp directory first
shell_exec(sprintf('rm -rf %s/*', $outputPath));
$this->filesystem->remove($this->findFiles($outputPath));
$docsPath = $this->getProjectDocsPath($project) . '/en';
@@ -134,19 +143,9 @@ SIDEBAR;
$sidebarPath = $docsPath . '/sidebar.rst';
$sidebar = file_exists($sidebarPath) ? file_get_contents($sidebarPath) : self::DEFAULT_SIDEBAR;
$files = $this->recursiveGlob($docsPath);
$files = $this->getSourceFiles($docsPath);
foreach ($files as $file) {
// skip non .rst files
if (strpos($file, '.rst') === false) {
continue;
}
// skip toc.rst
if (strpos($file, 'toc.rst') !== false) {
continue;
}
$path = str_replace($this->getProjectDocsPath($project) . '/en/', '', $file);
$newPath = $outputPath . '/' . $path;
@@ -184,7 +183,7 @@ SIDEBAR;
$content = str_replace('{{ sidebar }}', $sidebar, $content);
// append the source file name to the content so we can parse it back out
// for use in the sculpin build process
// for use in the build process
$content .= sprintf('{{ SOURCE_FILE:/en/%s }}', $path);
file_put_contents($newPath, $content);
@@ -195,8 +194,8 @@ SIDEBAR;
{
$outputPath = $this->getProjectVersionSourcePath($project, $version);
// clear projects docs source in the sculpin source folder before rebuilding
shell_exec(sprintf('rm -rf %s/*', $outputPath));
// clear projects docs source in the source folder before rebuilding
$this->filesystem->remove($this->findFiles($outputPath));
// we have to get a fresh builder due to how the RST parser works
$this->builder = $this->builder->recreate();
@@ -212,23 +211,18 @@ SIDEBAR;
{
$projectDocsVersionPath = $this->getProjectVersionSourcePath($project, $version);
$files = $this->recursiveGlob($projectDocsVersionPath);
$this->removeMetaFiles($projectDocsVersionPath);
$files = $this->getBuildFiles($projectDocsVersionPath);
foreach ($files as $file) {
// we don't want the meta.php files in the end result
if (strpos($file, 'meta.php')) {
unlink($file);
continue;
}
$content = trim(file_get_contents($file));
// extract title from <h1>
preg_match('/<h1>(.*)<\/h1>/', $content, $matches);
$title = '';
if (! empty($matches)) {
if ($matches !== []) {
$title = $matches[1];
}
@@ -240,7 +234,6 @@ SIDEBAR;
);
// grab the html out of the <body> because that is all we need
// sculpin will wrap it with the layout
preg_match('/<body>(.*)<\/body>/s', $content, $matches);
$content = $matches[1] ?? $content;
@@ -255,7 +248,7 @@ SIDEBAR;
$content = str_replace($match[0], '', $content);
$newContent = sprintf(
self::SCULPIN_TEMPLATE,
self::PARAMETERS_TEMPLATE,
$title,
$project->getDocsSlug(),
strpos($file, 'index.html') !== false ? 'true' : 'false',
@@ -271,43 +264,103 @@ SIDEBAR;
}
}
private function removeMetaFiles(string $path) : void
{
$finder = new Finder();
$finder->in($path)->name('meta.php')->files();
$files = $this->finderToArray($finder);
$this->filesystem->remove($files);
}
private function getProjectDocsPath(Project $project) : string
{
return $project->getAbsoluteDocsPath($this->projectsPath);
return realpath($project->getAbsoluteDocsPath($this->projectsPath));
}
/**
* @return string[]
*/
private function recursiveGlob(string $path) : array
private function getSourceFiles(string $path) : array
{
$allFiles = [];
$files = glob($path . '/*');
foreach ($files as $file) {
if (is_dir($file)) {
$allFiles = array_merge($allFiles, $this->recursiveGlob($file));
} else {
$allFiles[] = $file;
}
if (! is_dir($path)) {
return [];
}
return $allFiles;
$finder = $this->getFilesFinder($path);
$finder->name('*.rst');
$finder->notName('toc.rst');
return $this->finderToArray($finder);
}
/**
* @return string[]
*/
private function getBuildFiles(string $path) : array
{
if (! is_dir($path)) {
return [];
}
$finder = $this->getFilesFinder($path);
$files = $this->finderToArray($finder);
return array_filter($files, function (string $file) {
return strpos($file, 'meta.php') === false;
});
}
private function getFilesFinder(string $path) : Finder
{
$finder = new Finder();
$finder->in($path)->files();
return $finder;
}
/**
* @return string[]
*/
private function findFiles(string $path) : array
{
if (! is_dir($path)) {
return [];
}
return $this->finderToArray($this->getFilesFinder($path));
}
/**
* @return string[]
*/
private function finderToArray(Finder $finder) : array
{
return array_values(array_map(function (SplFileInfo $file) {
return $file->getRealPath();
}, iterator_to_array($finder)));
}
private function ensureDirectoryExists(string $dir) : void
{
if (is_dir($dir)) {
return;
}
if (file_exists($dir)) {
return;
}
// Without the @ this fails on travis ci with error: "mkdir(): File exists"
@mkdir($dir, 0777, true);
}
private function getProjectVersionSourcePath(Project $project, ProjectVersion $version) : string
{
return $this->sculpinSourcePath . '/projects/' . $project->getDocsSlug() . '/en/' . $version->getSlug();
return $this->sourcePath . '/projects/' . $project->getDocsSlug() . '/en/' . $version->getSlug();
}
private function getProjectVersionTmpPath(Project $project, ProjectVersion $version) : string

View File

@@ -43,15 +43,6 @@ class SearchIndexer
$index = $this->getSearchIndex();
$index->setSettings([
'attributesToIndex' => [
'unordered(projectName)',
'unordered(h1)',
'unordered(h2)',
'unordered(h3)',
'unordered(h4)',
'unordered(h5)',
'unordered(content)',
],
'attributesToIndex' => ['projectName', 'h1', 'h2', 'h3', 'h4', 'h5', 'content'],
'customRanking' => ['asc(rank)'],
'ranking' => ['words', 'typo', 'attribute', 'proximity', 'custom'],
@@ -105,7 +96,7 @@ class SearchIndexer
$nodeTypes = [TitleNode::class, ParagraphNode::class];
$nodes = $document->getNodes(function (Node $node) use ($nodeTypes) {
return in_array(get_class($node), $nodeTypes);
return in_array(get_class($node), $nodeTypes, true);
});
foreach ($nodes as $node) {

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Directive;
use Doctrine\RST\Nodes\Node;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\CodeNode;
use Doctrine\RST\Nodes\Node;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\SubDirective;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\RawNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Doctrine\Website\DoctrineSculpinBundle\Directive;
namespace Doctrine\Website\RST\Directive;
use Doctrine\RST\Nodes\Node;
use Doctrine\RST\Nodes\WrapperNode;

78
lib/Site.php Normal file
View File

@@ -0,0 +1,78 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website;
class Site
{
/** @var string */
private $title;
/** @var string */
private $subtitle;
/** @var string */
private $url;
/** @var string[] */
private $keywords;
/** @var string */
private $description;
/** @var string */
private $env;
/**
* @param string[] $keywords
*/
public function __construct(
string $title,
string $subtitle,
string $url,
array $keywords,
string $description,
string $env
) {
$this->title = $title;
$this->subtitle = $subtitle;
$this->url = $url;
$this->keywords = $keywords;
$this->description = $description;
$this->env = $env;
}
public function getTitle() : string
{
return $this->title;
}
public function getSubtitle() : string
{
return $this->subtitle;
}
public function getUrl() : string
{
return $this->url;
}
/**
* @return string[]
*/
public function getKeywords() : array
{
return $this->keywords;
}
public function getDescription() : string
{
return $this->description;
}
public function getEnv() : string
{
return $this->env;
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Twig;
use Doctrine\Website\Builder\SourceFile;
use Doctrine\Website\Builder\SourceFileRepository;
use Twig_Extension;
use Twig_SimpleFunction;
use function array_reverse;
use function usort;
class BlogExtension extends Twig_Extension
{
/** @var SourceFileRepository */
private $sourceFileRepository;
public function __construct(SourceFileRepository $sourceFileRepository)
{
$this->sourceFileRepository = $sourceFileRepository;
}
/**
* @return Twig_SimpleFunction[]
*/
public function getFunctions() : array
{
return [
new Twig_SimpleFunction('get_blog_posts', [$this, 'getBlogPosts']),
];
}
/**
* @return SourceFile[]
*/
public function getBlogPosts() : array
{
$blogPosts = $this->sourceFileRepository->getFiles('', 'source/blog');
usort($blogPosts, function (SourceFile $a, SourceFile $b) {
return $a->getDate()->getTimestamp() - $b->getDate()->getTimestamp();
});
return array_reverse($blogPosts);
}
}

114
lib/Twig/MainExtension.php Normal file
View File

@@ -0,0 +1,114 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Twig;
use Parsedown;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Twig_Extension;
use Twig_SimpleFilter;
use Twig_SimpleFunction;
use function file_exists;
use function file_get_contents;
use function filemtime;
use function md5;
use function realpath;
use function str_replace;
use function strpos;
use function substr;
class MainExtension extends Twig_Extension
{
/** @var Parsedown */
private $parsedown;
public function __construct(Parsedown $parsedown)
{
$this->parsedown = $parsedown;
}
/**
* @return Twig_SimpleFunction[]
*/
public function getFunctions() : array
{
return [
new Twig_SimpleFunction('get_asset_url', [$this, 'getAssetUrl']),
new Twig_SimpleFunction('get_docs_urls', [$this, 'getDocsUrls']),
new Twig_SimpleFunction('get_api_docs_urls', [$this, 'getApiDocsUrls']),
];
}
/**
* @return Twig_SimpleFilter[]
*/
public function getFilters() : array
{
return [
new Twig_SimpleFilter('markdown', [$this->parsedown, 'text']),
];
}
public function getAssetUrl(string $path, string $siteUrl) : string
{
return $siteUrl . $path . '?' . $this->getAssetCacheBuster($path);
}
/**
* @return mixed[]
*/
public function getDocsUrls() : array
{
return $this->getUrlsFromFiles('projects');
}
/**
* @return mixed[]
*/
public function getApiDocsUrls() : array
{
return $this->getUrlsFromFiles('api');
}
/**
* @return mixed[]
*/
private function getUrlsFromFiles(string $path, string $extension = 'html') : array
{
$root = realpath(__DIR__ . '/../../source');
$path = $root . '/' . $path;
if (! file_exists($path)) {
return [];
}
$it = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$urls = [];
foreach (new RecursiveIteratorIterator($it) as $file) {
$path = (string) $file;
if (strpos($path, '.' . $extension) === false) {
continue;
}
$url = str_replace($root, '', $path);
$urls[] = [
'url' => $url,
'date' => filemtime($path),
];
}
return $urls;
}
private function getAssetCacheBuster(string $path) : string
{
$assetPath = realpath(__DIR__ . '/../../source/' . $path);
return substr(md5(file_get_contents($assetPath)), 0, 6);
}
}

View File

@@ -20,12 +20,12 @@ class ProjectExtension extends Twig_Extension
private $projectRepository;
/** @var string */
private $sculpinSourcePath;
private $sourcePath;
public function __construct(ProjectRepository $projectRepository, string $sculpinSourcePath)
public function __construct(ProjectRepository $projectRepository, string $sourcePath)
{
$this->projectRepository = $projectRepository;
$this->sculpinSourcePath = $sculpinSourcePath;
$this->sourcePath = $sourcePath;
}
/**
@@ -65,7 +65,7 @@ class ProjectExtension extends Twig_Extension
$otherVersionUrl = str_replace($currentVersion, $projectVersion->getSlug(), $url);
}
$otherVersionFile = $this->sculpinSourcePath . $otherVersionUrl;
$otherVersionFile = $this->sourcePath . $otherVersionUrl;
if (! $this->fileExists($otherVersionFile)) {
return null;

View File

@@ -6,22 +6,13 @@ namespace Doctrine\Website\Twig;
use Closure;
use Doctrine\Website\Projects\Project;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Twig_Extension;
use Twig_SimpleFunction;
use function array_filter;
use function file_get_contents;
use function filemtime;
use function in_array;
use function ksort;
use function md5;
use function realpath;
use function str_replace;
use function strpos;
use function substr;
class MainExtension extends Twig_Extension
class TeamExtension extends Twig_Extension
{
/** @var mixed[] */
private $teamMembers;
@@ -40,23 +31,15 @@ class MainExtension extends Twig_Extension
public function getFunctions() : array
{
return [
new Twig_SimpleFunction('get_asset_url', [$this, 'getAssetUrl']),
new Twig_SimpleFunction('get_active_core_team_members', [$this, 'getActiveCoreTeamMembers']),
new Twig_SimpleFunction('get_active_documentation_team_members', [$this, 'getActiveDocumentationTeamMembers']),
new Twig_SimpleFunction('get_inactive_team_members', [$this, 'getInactiveTeamMembers']),
new Twig_SimpleFunction('get_active_project_team_members', [$this, 'getActiveProjectTeamMembers']),
new Twig_SimpleFunction('get_inactive_project_team_members', [$this, 'getInactiveProjectTeamMembers']),
new Twig_SimpleFunction('get_all_project_team_members', [$this, 'getAllProjectTeamMembers']),
new Twig_SimpleFunction('get_docs_urls', [$this, 'getDocsUrls']),
new Twig_SimpleFunction('get_api_docs_urls', [$this, 'getApiDocsUrls']),
];
}
public function getAssetUrl(string $path, string $siteUrl) : string
{
return $siteUrl . $path . '?' . $this->getAssetCacheBuster($path);
}
/**
* @return mixed[]
*/
@@ -123,7 +106,7 @@ class MainExtension extends Twig_Extension
public function getAllProjectTeamMembers(Project $project) : array
{
return $this->getTeamMembers(function (array $teamMember) use ($project) {
return in_array($project->getSlug(), $teamMember['projects'] ?? []);
return in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
});
}
@@ -135,7 +118,7 @@ class MainExtension extends Twig_Extension
return $this->getTeamMembers(function (array $teamMember) use ($project) {
$active = $teamMember['active'] ?? false;
return $active && in_array($project->getSlug(), $teamMember['projects'] ?? []);
return $active && in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
});
}
@@ -147,59 +130,7 @@ class MainExtension extends Twig_Extension
return $this->getTeamMembers(function (array $teamMember) use ($project) {
$active = $teamMember['active'] ?? false;
return ! $active && in_array($project->getSlug(), $teamMember['projects'] ?? []);
return ! $active && in_array($project->getSlug(), $teamMember['projects'] ?? [], true);
});
}
/**
* @return mixed[]
*/
public function getDocsUrls() : array
{
return $this->getUrlsFromFiles('projects');
}
/**
* @return mixed[]
*/
public function getApiDocsUrls() : array
{
return $this->getUrlsFromFiles('api');
}
/**
* @return mixed[]
*/
private function getUrlsFromFiles(string $path) : array
{
$root = realpath(__DIR__ . '/../../../../../source');
$path = $root . '/' . $path;
$it = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS);
$urls = [];
foreach (new RecursiveIteratorIterator($it) as $file) {
$path = (string) $file;
if (strpos($path, '.html') === false) {
continue;
}
$url = str_replace($root, '', $path);
$urls[] = [
'url' => $url,
'date' => filemtime($path),
];
}
return $urls;
}
private function getAssetCacheBuster(string $path) : string
{
$assetPath = realpath(__DIR__ . '/../../../../../source/' . $path);
return substr(md5(file_get_contents($assetPath)), 0, 6);
}
}

66
lib/Twig/TwigRenderer.php Normal file
View File

@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Doctrine\Website\Twig;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
use Twig\Loader\ChainLoader;
use Twig\Loader\FilesystemLoader;
use function sha1;
class TwigRenderer
{
/** @var MainExtension */
private $mainExtension;
/** @var ProjectExtension */
private $projectExtension;
/** @var TeamExtension */
private $teamExtension;
/** @var BlogExtension */
private $blogExtension;
/** @var string */
private $templatesPath;
public function __construct(
MainExtension $mainExtension,
ProjectExtension $projectExtension,
TeamExtension $teamExtension,
BlogExtension $blogExtension,
string $templatesPath
) {
$this->mainExtension = $mainExtension;
$this->projectExtension = $projectExtension;
$this->teamExtension = $teamExtension;
$this->blogExtension = $blogExtension;
$this->templatesPath = $templatesPath;
}
/**
* @param mixed[] $parameters
*/
public function render(string $twig, array $parameters) : string
{
$name = sha1($twig);
$loader = new ArrayLoader([$name => $twig]);
$chainLoader = new ChainLoader([
$loader,
new FilesystemLoader($this->templatesPath),
]);
$twig = new Environment($chainLoader);
$twig->addExtension($this->mainExtension);
$twig->addExtension($this->projectExtension);
$twig->addExtension($this->teamExtension);
$twig->addExtension($this->blogExtension);
return $twig->render($name, $parameters);
}
}

View File

@@ -4,51 +4,62 @@ declare(strict_types=1);
namespace Doctrine\Website;
use Dflydev\DotAccessConfiguration\Configuration;
use Doctrine\Website\Builder\SourceFileBuilder;
use Doctrine\Website\Builder\SourceFileRepository;
use Doctrine\Website\Projects\Project;
use Doctrine\Website\Projects\ProjectRepository;
use Doctrine\Website\Projects\ProjectVersion;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use function chdir;
use function file_exists;
use function file_put_contents;
use function glob;
use function in_array;
use function is_dir;
use function realpath;
use function sprintf;
use function str_replace;
use function symlink;
use function unlink;
class WebsiteBuilder
{
public const URL_LOCAL = 'lcl.doctrine-project.org';
public const URL_STAGING = 'staging.doctrine-project.org';
public const URL_PRODUCTION = 'www.doctrine-project.org';
public const PUBLISHABLE_ENVS = ['prod', 'staging'];
private const URL_PRODUCTION = 'www.doctrine-project.org';
private const URL_STAGING = 'staging.doctrine-project.org';
private const PUBLISHABLE_ENV_URLS = [
'prod' => self::URL_PRODUCTION,
'staging' => self::URL_STAGING,
];
/** @var ProcessFactory */
private $processFactory;
/** @var Configuration */
private $sculpinConfig;
/** @var ProjectRepository */
private $projectRepository;
/** @var string */
private $kernelRootDir;
/** @var Filesystem */
private $filesystem;
/** @var SourceFileRepository */
private $sourceFileRepository;
/** @var SourceFileBuilder */
private $sourceFileBuilder;
public function __construct(
ProcessFactory $processFactory,
Configuration $sculpinConfig,
ProjectRepository $projectRepository,
string $kernelRootDir
Filesystem $filesystem,
SourceFileRepository $sourceFileRepository,
SourceFileBuilder $sourceFileBuilder
) {
$this->processFactory = $processFactory;
$this->sculpinConfig = $sculpinConfig;
$this->projectRepository = $projectRepository;
$this->kernelRootDir = $kernelRootDir;
$this->processFactory = $processFactory;
$this->projectRepository = $projectRepository;
$this->filesystem = $filesystem;
$this->sourceFileRepository = $sourceFileRepository;
$this->sourceFileBuilder = $sourceFileBuilder;
}
public function build(
@@ -63,40 +74,19 @@ class WebsiteBuilder
$buildDir
));
$rootDir = realpath($this->kernelRootDir . '/..');
if ($publish) {
$output->writeln(' - updating from git');
$this->processFactory->run(sprintf('cd %s && git pull origin master', $buildDir));
}
$output->writeln(' - sculpin generate');
$output->writeln(' - building website');
$command = sprintf(
'php -d memory_limit=1024M %s/vendor/bin/sculpin generate --env=%s',
$rootDir,
$env
);
$this->processFactory->run($command);
$output->writeln(' - preparing build');
$outputDir = sprintf('output_%s', $env);
// cleanup the build directory
$this->processFactory->run(sprintf('rm -rf %s/*', $buildDir));
// copy the build to the build directory
$this->processFactory->run(sprintf('mv %s/%s/* %s', $rootDir, $outputDir, $buildDir));
$this->buildWebsite($buildDir);
// put the CNAME file back for publishable envs
if (in_array($env, self::PUBLISHABLE_ENVS)) {
$url = $this->sculpinConfig->get('url');
$cname = str_replace(['https://', 'http://'], '', $url);
$this->filePutContents($buildDir . '/CNAME', $cname);
if (in_array($env, self::PUBLISHABLE_ENVS, true)) {
$this->filePutContents($buildDir . '/CNAME', self::PUBLISHABLE_ENV_URLS[$env]);
}
$this->createProjectVersionAliases($buildDir);
@@ -115,9 +105,14 @@ class WebsiteBuilder
file_put_contents($path, $contents);
}
protected function execute(string $command) : void
private function buildWebsite(string $buildDir) : void
{
$this->processFactory->run($command);
// cleanup the build directory
$this->filesystem->remove(glob($buildDir . '/*'));
foreach ($this->sourceFileRepository->getFiles($buildDir) as $file) {
$this->sourceFileBuilder->buildFile($file, $buildDir);
}
}
private function createProjectVersionAliases(string $buildDir) : void

View File

@@ -9,12 +9,8 @@
<!-- Ignore warnings, show progress of the run and show sniff names -->
<arg value="nps"/>
<file>app</file>
<file>lib</file>
<file>tests</file>
<rule ref="Doctrine"/>
<rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace">
<exclude-pattern>app/SculpinKernel.php</exclude-pattern>
</rule>
</ruleset>

9
phpstan.neon.dist Normal file
View File

@@ -0,0 +1,9 @@
includes:
- vendor/phpstan/phpstan-phpunit/extension.neon
- vendor/phpstan/phpstan-strict-rules/rules.neon
parameters:
level: 1
paths:
- lib
- tests

View File

@@ -1,15 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="./vendor/autoload.php" colors="true">
<filter>
<whitelist addUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./app/src</directory>
</whitelist>
</filter>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
verbose="true"
beStrictAboutOutputDuringTests="true"
>
<testsuites>
<testsuite name="Doctrine Website Test Suite">
<directory suffix="Test.php">./tests/Doctrine/Website/Tests/</directory>
<directory>./tests</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./lib</directory>
</whitelist>
</filter>
</phpunit>

View File

@@ -1,103 +0,0 @@
{% extends "default" %}
{% block head_meta %}
<script type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "NewsArticle",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "{{ site.url }}{{ page.url }}"
},
"headline": "{{ page.title }}",
"image": [
"{{ site.url }}/images/og.png"
],
"datePublished": "{{ page.date|date('c') }}",
"dateModified": "{{ page.date|date('c') }}",
"author": {
"@type": "Person",
"name": "{{ page.authorName ?? 'Doctrine' }}"
},
"publisher": {
"@type": "Organization",
"name": "Doctrine",
"logo": {
"@type": "ImageObject",
"url": "{{ site.url }}/images/og.png"
}
},
"description": "{{ page.blocks.content|raw|striptags[:100] }}"
}
</script>
{% endblock %}
{% block content_wrapper %}
<article>
<header>
<h2>{{ page.title }} <small>post</small></h2>
</header>
<p class="lead">
Posted on {{ page.date|date('Y-m-d') }}
{% if page.authorName %}
by
{% if page.authorEmail %}
<a href="mailto:{{ page.authorEmail }}">{{ page.authorName }}</a>
{% else %}
{{ page.authorName }}
{% endif %}
{% endif %}
</p>
<hr />
<div>
{{ page.blocks.content|raw }}
</div>
{% if page.previous_post or page.next_post %}
<nav class="article">
<ul class="pagination">
{% if page.previous_post %}
<li class="page-item"><a class="page-link previous" href="{{ site.url }}{{ page.previous_post.url }}" title="{{ page.previous_post.title }}"><span class="title">Previous: {{ page.previous_post.title }}</span></a></li>
{% endif %}
{% if page.next_post %}
<li class="page-item"><a class="page-link next" href="{{ site.url }}{{ page.next_post.url }}" title="{{ page.next_post.title }}"><span class="title">Next: {{ page.next_post.title }}</span></a></li>
{% endif %}
</ul>
</nav>
{% endif %}
</article>
{% if site.disqus.shortname and site.disqus.shortname != '' %}
<div id="disqus_thread"></div>
<script type="text/javascript">
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = '{{site.disqus.shortname}}'; // required: replace example with your forum shortname
{% if page.disqus.identifier %}var disqus_identifier = '{{page.disqus.identifier}}'; {% endif %}
{% if page.disqus.title %}var disqus_title = '{{page.disqus.title}}';{% endif %}
{% if page.disqus.url %}var disqus_url = '{{page.disqus.url}}';{% endif %}
{% if page.disqus.category_id %}var disqus_category_id = '{{page.disqus.category_id}}';{% endif %}
/* * * DON'T EDIT BELOW THIS LINE * * */
(function () {
var dsq = document.createElement('script');
dsq.type = 'text/javascript';
dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the
<a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a>
</noscript>
{% endif %}
{% endblock %}

View File

@@ -1,45 +0,0 @@
---
layout: default
title: Posts Archive
generator: pagination
use:
- posts
---
{% set year = '0' %}
<h1><i class="fa fa-archive"></i> Archive</h1>
{% for post in page.pagination.items %}
{% set this_year %}{{ post.date | date("Y") }}{% endset %}
{% if year != this_year %}
{% set month = '0' %}
{% set year = this_year %}
{% endif %}
{% set this_month %}{{ post.date | date("F") }}{% endset %}
{% if month != this_month %}
{% set month = this_month %}
<h3>{{ month }} {{ year }}</h3>
{% endif %}
<div>
<a href="{{ site.url }}{{ post.url }}">{{ post.title }}</a>
</div>
{% endfor %}
{% if page.pagination.previous_page or page.pagination.next_page %}
<nav class="mt-4">
<ul class="pagination">
{% if page.pagination.previous_page %}
<li class="page-item"><a class="page-link previous" href="{{ site.url }}{{ page.pagination.previous_page.url }}" title="Previous Page"><span class="title">Previous Page</span></a></li>
{% endif %}
{% if page.pagination.next_page %}
<li class="page-item"><a class="page-link next" href="{{ site.url }}{{ page.pagination.next_page.url }}" title="Next Page"><span class="title">Next Page</span></a></li>
{% endif %}
</ul>
</nav>
{% endif %}

View File

@@ -1,6 +1,5 @@
---
use: ["posts"]
permalink: atom.xml
permalink: /atom.xml
---
<?xml version="1.0" encoding="utf-8"?>
@@ -18,15 +17,13 @@ permalink: atom.xml
</author>
{% endif %}
<generator uri="http://sculpin.io/">Sculpin</generator>
{% for post in data.posts|slice(0, 10) %}
{% for post in get_blog_posts()|slice(0, 10) %}
<entry>
<title type="html"><![CDATA[{{ post.title }}]]></title>
<title type="html"><![CDATA[{{ post.parameters.title }}]]></title>
<link href="{{ site.url }}{{ post.url }}"/>
<updated>{{ post.date|date('c') }}</updated>
<id>{{ site.url }}{{ post.url }}</id>
<content type="html"><![CDATA[{{ post.blocks.content|raw }}]]></content>
<content type="html"><![CDATA[{{ post.contents|markdown|raw }}]]></content>
</entry>
{% endfor %}
</feed>

View File

@@ -2,53 +2,23 @@
layout: default
title: Blog
menuSlug: blog
generator: pagination
pagination:
max_per_page: 3
use:
- posts
permalink: /blog/index.html
---
{% for post in page.pagination.items %}
<article>
<header>
<h2><a href="{{ site.url }}{{ post.url }}">{{ post.title }}</a></h2>
</header>
<h1>Blog</h1>
<p class="lead">
Posted on {{ post.date|date('Y-m-d') }}
{% if post.authorName %}
by
{% if post.authorEmail %}
<a href="mailto:{{ post.authorEmail }}">{{ post.authorName }}</a>
{% else %}
{{ post.authorName }}
{% endif %}
{% endif %}
</p>
<hr />
{% for post in get_blog_posts() %}
{{ post.date|date('Y-m-d') }} &nbsp; <a href="{{ post.url }}">{{ post.parameters.title }}</a>
<div>
{{ post.blocks.content|raw }}
</div>
{% if post.meta.tags %}
<p class="tags">
Tags:
{% for tag in post.meta.tags %}
<a href="{{ site.url }}/blog/tags/{{ tag|url_encode(true) }}">{{ tag }}</a>{% if not loop.last %}, {% endif %}
{% endfor %}
</p>
{% if post.parameters.authorName %}
by
{% if post.parameters.authorEmail %}
<a href="mailto:{{ page.authorEmail }}">{{ post.parameters.authorName }}</a>
{% else %}
{{ post.parameters.authorName }}
{% endif %}
</article>
{% endif %}
<br/>
{% endfor %}
{% if page.pagination.previous_page or page.pagination.next_page %}
<nav class="mt-4">
<ul class="pagination">
{% if page.pagination.previous_page %}<li class="page-item"><a class="page-link" href="{{ site.url }}{{ page.pagination.previous_page.url }}">Newer Posts</a></li>{% endif %}<br />
{% if page.pagination.next_page %}<li class="page-item"><a class="page-link" href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts</a></li>{% endif %}
</ul>
</nav>
{% endif %}

View File

@@ -1,6 +1,7 @@
---
title: New Website
title: "New Website"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: New Coverage Report
title: "New Coverage Report"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Beta 2
title: "Beta 2"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Beta 2 Released
title: "Beta 2 Released"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: [release]

View File

@@ -1,6 +1,7 @@
---
title: URL Changes
title: "URL Changes"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: New Design
title: "New Design"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Project Status
title: "Project Status"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Cleaning up the mess
title: "Cleaning up the mess"
menuSlug: blog
layout: blog-post
authorName: guilhermeblanco
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: A few updates for 2008
title: "A few updates for 2008"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Using Doctrine with CodeIgniter
title: "Using Doctrine with CodeIgniter"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Doctrine all grown up
title: "Doctrine all grown up"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Doctrine 0.9.1 / 0.10.1 Released
title: "Doctrine 0.9.1 / 0.10.1 Released"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: [release]

View File

@@ -1,6 +1,7 @@
---
title: Doctrine ORM Sandbox
title: "Doctrine ORM Sandbox"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: 0.10.2 Released
title: "0.10.2 Released"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: [release]

View File

@@ -1,6 +1,7 @@
---
title: My First Project Doctrine Tutorial
title: "My First Project Doctrine Tutorial"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: Doctrine Cheat Sheet
title: "Doctrine Cheat Sheet"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: 4,000th svn commit/revision
title: "4,000th svn commit/revision"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

View File

@@ -1,6 +1,7 @@
---
title: 0.10.3 Released
title: "0.10.3 Released"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: [release]

View File

@@ -1,6 +1,7 @@
---
title: 0.10.4 Released - 46 Closed Tickets
title: "0.10.4 Released - 46 Closed Tickets"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: [release]

View File

@@ -1,6 +1,7 @@
---
title: Using Doctrine with Zend Framework
title: "Using Doctrine with Zend Framework"
menuSlug: blog
layout: blog-post
authorName: jwage
authorEmail:
categories: []

Some files were not shown because too many files have changed in this diff Show More