Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
61df3ba
DEV DocMarkdownPrinter can use now ObjectMarkdownPrinter
Frxnklyn Nov 17, 2025
a70623a
DEV UxonPrototypeMarkdownPrinter add Types to the Markdown
Frxnklyn Nov 17, 2025
064a9e9
FIX ObjectMarkdownPrinter fixed that the normalized function not more…
Frxnklyn Nov 17, 2025
852a3f8
NEW LogEntryMarkdownPrinter currently ignores values with support
Frxnklyn Nov 17, 2025
a04b6c3
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 20, 2025
c830587
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 20, 2025
14133dd
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 24, 2025
914010d
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 25, 2025
c383943
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 25, 2025
afcfb7f
DEV MetaObjectPrinter function normalize add Description
Frxnklyn Nov 25, 2025
c6c6c0a
DEV MarkdownDataType NEW functions buildMarkdownHeader & convertHeade…
Frxnklyn Nov 25, 2025
7005bdc
DEV ObjectMarkdownPrinter add to everything description
Frxnklyn Nov 25, 2025
d297e85
FIX LogEntryMarkdownPrinter and added all Description
Frxnklyn Nov 25, 2025
8c0471c
FIX Docsface and NEW MarkdownPrinterMiddlewareInterface to use the ne…
Frxnklyn Nov 27, 2025
f159de9
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Nov 27, 2025
766bc7f
NEW CodeMarkdownPrinter
Frxnklyn Dec 2, 2025
95d8fdf
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Dec 2, 2025
98598ec
FIX AbstractMarkdownPrinterMiddleware change shouldskip from protectd…
Frxnklyn Dec 5, 2025
d61938d
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Dec 11, 2025
a04d467
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Dec 16, 2025
176361f
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Dec 17, 2025
1c0ed68
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Jan 9, 2026
34c603f
Merge branch '1.x-dev' of https://github.com/ExFace/Core into feature…
Frxnklyn Jan 21, 2026
496d6e7
DEV ObjectMarkdownPrinter now with Actions & new ActionMarkdownPrinter
Frxnklyn Jan 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions Facades/DocsFacade/MarkdownPrinters/ActionMarkdownPrinter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

namespace exface\Core\Facades\DocsFacade\MarkdownPrinters;


use exface\Core\CommonLogic\UxonObject;
use exface\Core\DataTypes\MarkdownDataType;
use exface\Core\DataTypes\PhpClassDataType;
use exface\Core\DataTypes\RelationTypeDataType;
use exface\Core\Exceptions\Model\MetaRelationBrokenError;
use exface\Core\Facades\DocsFacade;
use exface\Core\Factories\MetaObjectFactory;
use exface\Core\Factories\QueryBuilderFactory;
use exface\Core\Interfaces\Actions\ActionInterface;
use exface\Core\Interfaces\Model\BehaviorInterface;
use exface\Core\Interfaces\Model\MetaAttributeInterface;
use exface\Core\Interfaces\Model\MetaAttributeListInterface;
use exface\Core\Interfaces\Model\MetaObjectInterface;
use exface\Core\Interfaces\Model\MetaRelationInterface;
use exface\Core\Interfaces\WorkbenchInterface;

/**
* Builds a Markdown documentation view for a meta object and its related objects.
*
* The printer renders a table of attributes for the given meta object and can
* optionally walk through relation attributes to print child objects up to a
* configurable depth.
*/
class ActionMarkdownPrinter //implements MarkdownPrinterInterface
{
protected WorkbenchInterface $workbench;

private ActionInterface $action;
private int $headingLevel = 1;

/**
* Maximum depth of recursive relation traversal.
*
* Depth 0 would print only the root object, higher values include related objects.
*/
private int $relationDepth = 0;
private ?string $relationType = RelationTypeDataType::REGULAR;



/**
* Creates a new object markdown printer for the given action.
*
*/
public function __construct(WorkbenchInterface $workbench, ActionInterface $action, int $headingLevel = 1)
{
$this->workbench = $workbench;
$this->action = $action;
$this->headingLevel = $headingLevel;
}

/**
* Builds and returns the complete Markdown for the current action
*/
public function getMarkdown(): string
{
$heading = MarkdownDataType::buildMarkdownHeader($this->action->getName(), $this->headingLevel);

$uxon = $this->action->exportUxonObject();

$uxon = $uxon->toJson();
//Uxon

//TODO Einbauen Uxon im Codeblock, mögliche Description

return <<<MD
{$heading}

Uxon:
´´´
{$uxon}
´´´
MD;
}


}
170 changes: 170 additions & 0 deletions Facades/DocsFacade/MarkdownPrinters/CodeMarkdownPrinter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
<?php

namespace exface\Core\Facades\DocsFacade\MarkdownPrinters;

use exface\Core\DataTypes\StringDataType;
use exface\Core\Interfaces\AppInterface;
use GuzzleHttp\Psr7\Uri;
use exface\Core\Interfaces\WorkbenchInterface;

/**
* CodeMarkdownPrinter loads a markdown file from an php file
*
* Expected request pattern:
* api/docs/Vendor/App/Some/Path/File.php
*
* The path part after Vendor and App is used directly as relative file path
* inside the app directory.
*/
class CodeMarkdownPrinter
{
private WorkbenchInterface $workbench;

private ?AppInterface $app = null;

private ?string $docsPath = null;

public function __construct(WorkbenchInterface $workbench, string $filePath = null)
{
$this->workbench = $workbench;

if ($filePath) {

$normalizedPath = $this->normalizePath(rawurldecode($filePath));

[$appAlias, $relativePath] = $this->extractAppAndRelativePath($normalizedPath);

if ($appAlias !== '') {
$this->app = $this->workbench->getApp($appAlias);
}

if ($relativePath !== '') {
$this->docsPath = $relativePath;
}
}
}

/**
* Reads the markdown document and returns its content.
* *
* @return string Markdown content
*/
public function getMarkdown(): string
{
$path = $this->getAbsolutePath();
if(!$path){
return 'ERROR: file not found!';
}
if(!StringDataType::endsWith($path, '.php')) {
return "ERROR: This path does not refer to a PHP file. Therefore, the file could not be read.";
}

return $this->rebasePaths($this->readFile($path));
}

/**
* Normalizes a file path to use a consistent directory separator.
*
* All slash variants are converted to the system directory separator
* and duplicate separators are collapsed.
*
* @param string $path Raw path
* @return string Normalized path
*/
protected function normalizePath(string $path): string
{
$path = str_replace(['\/', '\\'], '/', $path);
$path = preg_replace('#/+#', '/', $path);
$path = str_replace('/', DIRECTORY_SEPARATOR, $path);

$pattern = '#'.preg_quote(DIRECTORY_SEPARATOR).'+' . '#';
$path = preg_replace($pattern, DIRECTORY_SEPARATOR, $path);

return $path;
}

/**
* Extracts app alias and relative path from an api docs path.
*
* Expected pattern:
* api/docs/Vendor/App/some/path/file.php
* becomes:
* alias: "vendor.app"
* relativePath: "some/path/file.php"
*
* @param string $link Normalized path
* @return array{0:string,1:string} [appAlias, relativePath]
*/
protected function extractAppAndRelativePath(string $link): array
{
$link = $this->normalizePath($link);

$ds = preg_quote(DIRECTORY_SEPARATOR, '#');
$pattern = "#api{$ds}docs{$ds}([^{$ds}]+){$ds}([^{$ds}]+){$ds}(.+)$#i";

if (preg_match($pattern, $link, $m)) {
$appAlias = strtolower($m[1] . "." . $m[2]);
$relativePath = $m[3];
return [$appAlias, $relativePath];
}

return ['', ''];
}

/**
* Returns the absolute file system path to the current markdown file.
*
* @return string Absolute path to the markdown file
*/
public function getAbsolutePath(): ?string
{
if (! $this->app || ! $this->docsPath) {
return null;
}

return $this->app->getDirectoryAbsolutePath()
. DIRECTORY_SEPARATOR
. $this->docsPath;
}



/**
* Reads the content of a markdown file from disk.
*
* If the file does not exist an error message is returned instead.
*
* @param string $filePath Absolute path to the markdown file
* @return string File content or error message
*/
protected function readFile(string $filePath): string
{
if (! file_exists($filePath)) {
return 'ERROR: file not found!';
}

$md = file_get_contents($filePath);
return $md === false ? '' : $md;
}

/**
* Rewrites specific PHP use statements by inserting the api docs prefix.
*
* The raw input contains PHP code as a string. All matching use statements
* beginning with "use exface\" are rewritten so they begin with
* "use api\docs\exface\" instead. Other lines remain unchanged.
*/
protected function rebasePaths(string $raw) : string
{
return preg_replace(
'/^use\s+exface\\\\(.*);/m',
'use api\\docs\\exface\\\\$1;',
$raw
);
}





}
25 changes: 24 additions & 1 deletion Facades/DocsFacade/MarkdownPrinters/ObjectMarkdownPrinter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
use exface\Core\Facades\DocsFacade;
use exface\Core\Factories\MetaObjectFactory;
use exface\Core\Factories\QueryBuilderFactory;
use exface\Core\Interfaces\Actions\ActionInterface;
use exface\Core\Interfaces\Model\BehaviorInterface;
use exface\Core\Interfaces\Model\MetaAttributeInterface;
use exface\Core\Interfaces\Model\MetaAttributeListInterface;
use exface\Core\Interfaces\Model\MetaObjectInterface;
use exface\Core\Interfaces\Model\MetaRelationInterface;
use exface\Core\Interfaces\WorkbenchInterface;
use Respect\Validation\Rules\Length;

/**
* Builds a Markdown documentation view for a meta object and its related objects.
Expand Down Expand Up @@ -87,7 +89,10 @@ public function getMarkdown(): string
$importantAttributes = trim($importantAttributes);

$attributesHeading = MarkdownDataType::buildMarkdownHeader("Attributes of \"{$metaObject->getName()}\"", $headingLevel + 1);


$actionHeading = MarkdownDataType::buildMarkdownHeader("Actions of \"{$metaObject->getName()}\"", $headingLevel + 1);


$markdown = <<<MD

{$heading}
Expand All @@ -104,6 +109,8 @@ public function getMarkdown(): string

{$this->buildMdAttributesSections($metaObject, $headingLevel+2)}

{$this->buildMdActionSection($actionHeading, $metaObject, $headingLevel+2 )}

{$this->buildMdBehaviorsSections($metaObject, 'Behaviors of "' . $metaObject->getName() . '"', $headingLevel+1)}

{$this->buildMdRelatedObjects($metaObject->getRelations(), 'Related objects', $headingLevel)}
Expand Down Expand Up @@ -172,6 +179,22 @@ protected function buildMarkDownAttributeSection(MetaAttributeInterface $attr, i

{$this->buildMdUxonCodeblock($attr->getCustomDataTypeUxon(), 'Configuration of data type [' . $dataType->getAliasWithNamespace() . '](' . $dataTypeLink . '):')}

MD;

}

protected function buildMdActionSection(string $header, MetaObjectInterface $obj, int $headingLevel = 3) : string
{

$markdown = '';
foreach ($obj->getActions() as $act) {
$actionPrinter = new ActionMarkdownPrinter($this->workbench, $act, $headingLevel);
$markdown .= $actionPrinter->getMarkdown();
}
return <<<MD
{$header}

{$markdown}
MD;

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
return $response;
}

protected function shouldSkip(ServerRequestInterface $request): bool
public function shouldSkip(ServerRequestInterface $request): bool
{
return ! StringDataType::endsWith(
$request->getUri()->getPath(),
Expand Down
3 changes: 3 additions & 0 deletions Interfaces/Facades/MarkdownPrinterMiddlewareInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
interface MarkdownPrinterMiddlewareInterface extends MiddlewareInterface
{
public function getMarkdown(ServerRequestInterface $request) : string;


public function shouldSkip(ServerRequestInterface $request) : bool;
}