Skip to content

Commit

Permalink
Various changes to the default template
Browse files Browse the repository at this point in the history
- Sort constants, methods and properties on visibility and alphabet
  - In TOC
  - In List of elements
- Extract Description and Summary to loose templates
- Add a link around the header, and style it
- Show a read-only indicator with properties
- Show a write-only indicator with properties
- Do not show property(-*) tag in tag listing
- Do not show method tag in tag listing

Fixes #2439 and #2438

Addresses points in #2393
  • Loading branch information
mvriel committed Jun 19, 2020
1 parent 748172c commit 28d82cd
Show file tree
Hide file tree
Showing 20 changed files with 164 additions and 28 deletions.
12 changes: 7 additions & 5 deletions .phpdoc/template/components/header-title.html.twig
@@ -1,7 +1,9 @@
<h1 class="phpdocumentor-title">
<svg width="46" height="40" viewBox="0 0 46 40" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-bottom: -.5rem">
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.8938 0L45.5009 2.49244C37.3547 9.69866 33.6041 17.5764 32.4029 24.0936C31.8009 27.3599 31.8413 30.2714 32.2774 32.5817C32.7212 34.9329 33.5431 36.5091 34.3554 37.2827L32.5358 39.6471L0 19.6608L43.8938 0ZM6.40933 20.0771L29.5917 34.3177C29.493 33.9348 29.4055 33.541 29.3294 33.1382C28.8177 30.4269 28.7908 27.1404 29.4526 23.5498C30.4569 18.1012 33.0518 11.9219 37.9998 5.92724L6.40933 20.0771Z" fill="#8DD35F"/>
<path d="M10.9489 20.2992L33.7512 9.75848C26.2148 18.191 26.4081 27.9651 27.4709 30.8399L10.9489 20.2992Z" fill="#8DD35F"/>
</svg>
{{ project.name }}
<a href="{{ path('/') }}" class="phpdocumentor-title__link">
<svg width="46" height="40" viewBox="0 0 46 40" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-bottom: -.5rem">
<path fill-rule="evenodd" clip-rule="evenodd" d="M43.8938 0L45.5009 2.49244C37.3547 9.69866 33.6041 17.5764 32.4029 24.0936C31.8009 27.3599 31.8413 30.2714 32.2774 32.5817C32.7212 34.9329 33.5431 36.5091 34.3554 37.2827L32.5358 39.6471L0 19.6608L43.8938 0ZM6.40933 20.0771L29.5917 34.3177C29.493 33.9348 29.4055 33.541 29.3294 33.1382C28.8177 30.4269 28.7908 27.1404 29.4526 23.5498C30.4569 18.1012 33.0518 11.9219 37.9998 5.92724L6.40933 20.0771Z" fill="#8DD35F"/>
<path d="M10.9489 20.2992L33.7512 9.75848C26.2148 18.191 26.4081 27.9651 27.4709 30.8399L10.9489 20.2992Z" fill="#8DD35F"/>
</svg>
{{ project.name }}
</a>
</h1>
12 changes: 4 additions & 8 deletions Makefile
Expand Up @@ -54,21 +54,17 @@ lint: phpcs
test: unit-test
docker run -it --rm -v${CURDIR}:/data -w /data php:7.2 -f ./tests/coverage-checker.php 72

unit-test: ARGS=--testsuite=unit
integration-test: ARGS=--testsuite=integration --no-coverage
functional-test: ARGS=--testsuite=functional --no-coverage
unit-test: SUITE=--testsuite=unit
integration-test: SUITE=--testsuite=integration --no-coverage
functional-test: SUITE=--testsuite=functional --no-coverage

unit-test integration-test functional-test:
docker run -it --rm -v${CURDIR}:/github/workspace phpdoc/phpunit-ga $(ARGS)
docker run -it --rm -v${CURDIR}:/github/workspace phpdoc/phpunit-ga $(SUITE) $(ARGS)

.PHONY: e2e-test
e2e-test: node_modules/.bin/cypress build/default/index.html build/clean/index.html
docker run -it --rm -v ${CURDIR}:/e2e -w /e2e cypress/included:3.2.0

.PHONY: behat
behat:
${.DOCKER_COMPOSE_RUN} behat ${ARGS}

.PHONY: composer-require-checker
composer-require-checker:
docker run -it --rm -v${PWD}:/data -w /data phpga/composer-require-checker-ga check --config-file /data/composer-require-config.json composer.json
Expand Down
2 changes: 1 addition & 1 deletion data/templates/default/components/constants.html.twig
@@ -1,4 +1,4 @@
{% set constants = constants(node) %}
{% set constants = constants(node)|sortByVisibility %}

{% if constants is not empty %}
<section class="phpdocumentor-constants">
Expand Down
6 changes: 3 additions & 3 deletions data/templates/default/components/element-header.html.twig
@@ -1,5 +1,5 @@
<p class="phpdocumentor-summary">{{ node.summary }}</p>
<section class="phpdocumentor-description">{{ node.description|markdown }}</section>
{{ include ('components/tags.html.twig', {tags: node.tags}) }}
{{ include('components/summary.html.twig') }}
{{ include('components/description.html.twig') }}
{{ include('components/tags.html.twig', {tags: node.tags}) }}

{{ include ('components/table-of-contents.html.twig') }}
13 changes: 13 additions & 0 deletions data/templates/default/components/element.css.twig
Expand Up @@ -2,6 +2,10 @@
position: relative;
}

.phpdocumentor .phpdocumentor-element__name {
line-height: 1;
}

.phpdocumentor-element__package,
.phpdocumentor-element__extends,
.phpdocumentor-element__implements {
Expand All @@ -23,3 +27,12 @@
.phpdocumentor-element.-deprecated .phpdocumentor-element__name {
text-decoration: line-through;
}

.phpdocumentor-element__modifier {
font-size: var(--text-xxs);
padding: calc(var(--spacing-base-size) / 4) calc(var(--spacing-base-size) / 2);
color: var(--text-color);
background-color: var(--light-gray);
border-radius: 3px;
text-transform: uppercase;
}
13 changes: 13 additions & 0 deletions data/templates/default/components/header-title.css.twig
Expand Up @@ -9,3 +9,16 @@
margin: 0;
border-right: var(--sidebar-border-color) solid 1px;
}

.phpdocumentor-title__link {
transition: all .3s ease-out;
display: block;
color: var(--title-text-color);
text-decoration: none;
font-weight: normal;
}

.phpdocumentor-title__link:hover {
transform: perspective(15rem) translateX(.5rem);
font-weight: 600;
}
2 changes: 1 addition & 1 deletion data/templates/default/components/header-title.html.twig
@@ -1 +1 @@
<h1 class="phpdocumentor-title">{{ project.name }}</h1>
<h1 class="phpdocumentor-title"><a href="{{ path('/') }}">{{ project.name }}</a></h1>
4 changes: 3 additions & 1 deletion data/templates/default/components/method-arguments.html.twig
Expand Up @@ -7,7 +7,9 @@
: <span class="phpdocumentor-signature__argument__return-type">{{ argument.type|route('class:short')|join('|')|raw }}</span>
{% if argument.default %} = <span class="phpdocumentor-signature__argument__default-value">{{ argument.default }}</span>{% endif %}
</dt>
<dd class="phpdocumentor-argument-list__definition"><section class="phpdocumentor-description">{{ argument.description|default('')|markdown }}</section></dd>
<dd class="phpdocumentor-argument-list__definition">
{{ include('components/description.html.twig', {'node': argument.description}) }}
</dd>
{% endfor %}
</dl>
{% endif %}
3 changes: 2 additions & 1 deletion data/templates/default/components/method-response.html.twig
Expand Up @@ -2,6 +2,7 @@
<h5 class="phpdocumentor-return-value__heading">Return values</h5>
<span class="phpdocumentor-signature__response_type">{{ method.response.type|route('class:short')|join('|')|raw }}</span>
{% if method.response.description %}
&mdash; <span class="phpdocumentor-description">{{ method.response.description|markdown }}</span>
&mdash;
{{ include('components/description.html.twig', {'node': method.response.description}) }}
{% endif %}
{% endif %}
2 changes: 1 addition & 1 deletion data/templates/default/components/methods.html.twig
@@ -1,4 +1,4 @@
{% set methods = methods(node) %}
{% set methods = methods(node)|sortByVisibility %}
{% if methods is not empty %}
<section class="phpdocumentor-methods">
<h3 class="phpdocumentor-methods__header">Methods</h3>
Expand Down
2 changes: 1 addition & 1 deletion data/templates/default/components/properties.html.twig
@@ -1,4 +1,4 @@
{% set properties = properties(node) %}
{% set properties = properties(node)|sortByVisibility %}

{% if properties is not empty %}
<section class="phpdocumentor-properties">
Expand Down
10 changes: 9 additions & 1 deletion data/templates/default/components/property.html.twig
Expand Up @@ -6,9 +6,17 @@
-{{ property.visibility }}
{% if property.static %}-static{% endif %}
{% if property.deprecated %}-deprecated{% endif %}
{% if property.writeOnly %}-write-only{% endif %}
{% if property.readOnly %}-read-only{% endif %}
"
>
<h4 class="phpdocumentor-element__name">${{ property.name }}</h4>
<h4 class="phpdocumentor-element__name">
${{ property.name }}
<span class="phpdocumentor-element__modifiers">
{% if property.writeOnly %}<small class="phpdocumentor-element__modifier">write-only</small>{% endif %}
{% if property.readOnly %}<small class="phpdocumentor-element__modifier">read-only</small>{% endif %}
</span>
</h4>
{{ include('components/element-found-in.html.twig', {'node': property}) }}
{{ include('components/summary.html.twig', {'node': property}) }}
{{ include('components/property-signature.html.twig', {'node': property}) }}
Expand Down
6 changes: 3 additions & 3 deletions data/templates/default/components/table-of-contents.html.twig
Expand Up @@ -47,13 +47,13 @@
<h3>Table of Contents</h3>

<dl class="phpdocumentor-table-of-contents">
{% for constant in constants(node) %}
{% for constant in constants(node)|sortByVisibility %}
{{ include('components/table-of-contents-entry.html.twig', {'type': 'constant', 'node': constant}) }}
{% endfor %}
{% for property in properties(node) %}
{% for property in properties(node)|sortByVisibility %}
{{ include('components/table-of-contents-entry.html.twig', {'type': 'property', 'node': property}) }}
{% endfor %}
{% for method in methods(node) %}
{% for method in methods(node)|sortByVisibility %}
{{ include('components/table-of-contents-entry.html.twig', {'type': 'method', 'node': method}) }}
{% endfor %}
{% for function in node.functions|default([]) %}
Expand Down
4 changes: 2 additions & 2 deletions data/templates/default/components/tags.html.twig
@@ -1,4 +1,4 @@
{% set tags = tags|filter((v,k) => k not in ['var', 'param', 'return', 'package']) %}
{% set tags = tags|filter((v,k) => k not in ['var', 'param', 'property', 'property-read', 'property-write', 'method', 'return', 'package']) %}

{% if tags|length > 0 %}
<h5 class="phpdocumentor-tag-list__heading">Tags</h5>
Expand All @@ -21,7 +21,7 @@
{% if tag.link %}
<a class="phpdocumentor-tag-link" href="{{ tag.link }}">{{ tag.link }}</a>
{% endif %}
<section class="phpdocumentor-description">{{ tag.description|default('')|markdown }}</section>
{{ include('components/description.html.twig', {'node': tag}) }}
</dd>
{% endfor %}
{% endfor %}
Expand Down
1 change: 1 addition & 0 deletions data/templates/default/css/variables.css.twig
Expand Up @@ -25,6 +25,7 @@
--primary-color-lighten: hsl(96, 57%, 80%);
--primary-color-lighter: hsl(96, 57%, 97%);
--dark-gray: #d1d1d1;
--light-gray: #f0f0f0;

--text-color: #4b3b40;

Expand Down
2 changes: 2 additions & 0 deletions src/phpDocumentor/Descriptor/ClassDescriptor.php
Expand Up @@ -289,6 +289,8 @@ public function getMagicProperties() : Collection
$property->setName(ltrim($propertyTag->getVariableName(), '$'));
$property->setDescription($propertyTag->getDescription());
$property->setType($propertyTag->getType());
$property->setWriteOnly($propertyTag->getName() === 'property-write');
$property->setReadOnly($propertyTag->getName() === 'property-read');
$property->setParent($this);

$properties->add($property);
Expand Down
14 changes: 14 additions & 0 deletions src/phpDocumentor/Descriptor/Interfaces/PropertyInterface.php
Expand Up @@ -20,6 +20,20 @@
*/
interface PropertyInterface extends ElementInterface, TypeInterface
{
/**
* Returns true when this property is intended to be read-only.
*
* @link https://docs.phpdoc.org/latest/references/phpdoc/tags/property-read.html
*/
public function isReadOnly(): bool;

/**
* Returns true when this property is intended to be write-only.
*
* @link https://docs.phpdoc.org/latest/references/phpdoc/tags/property-write.html
*/
public function isWriteOnly(): bool;

/**
* Stores a textual representation of the default value for a property.
*/
Expand Down
26 changes: 26 additions & 0 deletions src/phpDocumentor/Descriptor/PropertyDescriptor.php
Expand Up @@ -42,6 +42,12 @@ class PropertyDescriptor extends DescriptorAbstract implements
/** @var string $visibility */
protected $visibility = 'public';

/** @var bool */
private $readOnly = false;

/** @var bool */
private $writeOnly = false;

/**
* @param ClassDescriptor|TraitDescriptor $parent
*/
Expand Down Expand Up @@ -170,4 +176,24 @@ public function getInheritedElement() : ?PropertyDescriptor

return null;
}

public function setReadOnly(bool $value): void
{
$this->readOnly = $value;
}

public function isReadOnly() : bool
{
return $this->readOnly;
}

public function setWriteOnly(bool $value): void
{
$this->writeOnly = $value;
}

public function isWriteOnly() : bool
{
return $this->writeOnly;
}
}
32 changes: 32 additions & 0 deletions src/phpDocumentor/Transformer/Writer/Twig/Extension.php
Expand Up @@ -18,6 +18,7 @@
use phpDocumentor\Descriptor\Collection;
use phpDocumentor\Descriptor\Descriptor;
use phpDocumentor\Descriptor\DescriptorAbstract;
use phpDocumentor\Descriptor\Interfaces\VisibilityInterface;
use phpDocumentor\Descriptor\NamespaceDescriptor;
use phpDocumentor\Descriptor\PackageDescriptor;
use phpDocumentor\Descriptor\ProjectDescriptor;
Expand Down Expand Up @@ -265,6 +266,37 @@ static function (Descriptor $a, Descriptor $b) use ($direction) {
return $iterator;
}
),
'sortByVisibility' => new TwigFilter(
'sortByVisibility',
/** @var Collection<Descriptor> $collection */
static function (Collection $collection) : ArrayIterator {
$visibilityOrder = [
'public' => 0,
'protected' => 1,
'private' => 2,
];
$iterator = $collection->getIterator();
$iterator->uasort(
static function (Descriptor $a, Descriptor $b) use ($visibilityOrder) {
$prio = 0;
if ($a instanceof VisibilityInterface && $b instanceof VisibilityInterface) {
$prio = ($visibilityOrder[$a->getVisibility()] ?? 0) <=> ($visibilityOrder[$b->getVisibility()] ?? 0);
}

if ($prio !== 0) {
return $prio;
}

$aElem = strtolower($a->getName());
$bElem = strtolower($b->getName());

return $aElem <=> $bElem;
}
);

return $iterator;
}
),
'export' => new TwigFilter(
'export',
static function ($var) {
Expand Down
26 changes: 26 additions & 0 deletions tests/unit/phpDocumentor/Descriptor/PropertyDescriptorTest.php
Expand Up @@ -53,6 +53,32 @@ public function testSettingAndGettingWhetherPropertyIsStatic() : void
$this->assertTrue($this->fixture->isStatic());
}

/**
* @covers ::isReadOnly
* @covers ::setReadOnly
*/
public function testSettingAndGettingWhetherPropertyIsReadOnly() : void
{
$this->assertFalse($this->fixture->isReadOnly());

$this->fixture->setReadOnly(true);

$this->assertTrue($this->fixture->isReadOnly());
}

/**
* @covers ::isWriteOnly
* @covers ::setWriteOnly
*/
public function testSettingAndGettingWhetherPropertyIsWriteOnly() : void
{
$this->assertFalse($this->fixture->isWriteOnly());

$this->fixture->setWriteOnly(true);

$this->assertTrue($this->fixture->isWriteOnly());
}

/**
* @covers ::getVisibility
* @covers ::setVisibility
Expand Down

0 comments on commit 28d82cd

Please sign in to comment.