fix markdown in descriptions
[mdref/mdref] / mdref / RefEntry.php
1 <?php
2
3 namespace mdref;
4
5 /**
6 * The RefEntry class represents a reference entry, i.e. a .md file
7 */
8 class RefEntry
9 {
10 /**
11 * @var \mdref\Path
12 */
13 protected $path;
14
15 /**
16 * @var string
17 */
18 protected $entry;
19
20 /**
21 * @var resource
22 */
23 protected $file;
24
25 /**
26 * @param \mdref\Path $path
27 * @param type $entry
28 */
29 function __construct(Path $path, $entry = null) {
30 $this->path = $path;
31 $this->entry = trim($entry ?: $path->getPathName(), DIRECTORY_SEPARATOR);
32 }
33
34 /**
35 * Clean up the file handle
36 */
37 function __destruct() {
38 if (is_resource($this->file)) {
39 fclose($this->file);
40 }
41 }
42
43 /**
44 * Format as URL
45 * @return string
46 */
47 function formatUrl() {
48 return htmlspecialchars($this->entry);
49 }
50
51 private function joinLink(array $parts) {
52 $link = "";
53 $upper = ctype_upper($parts[0][0]);;
54 for ($i = 0; $i < count($parts); ++$i) {
55 if (!strlen($parts[$i]) || $parts[$i] === ".") {
56 continue;
57 }
58 if (strlen($link)) {
59 if ($parts[$i][0] === ":") {
60 $link = "";
61 } elseif ($upper && !ctype_upper($parts[$i][0])) {
62 $link .= "::";
63 } else {
64 $link .= "\\";
65 }
66 }
67 $link .= trim($parts[$i], ": ");
68 $upper = ctype_upper($parts[$i][0]);
69 }
70 return $link;
71 }
72
73 /**
74 * Format as link text
75 * @param bool $basename whether to use the basename only
76 * @return string
77 */
78 function formatLink($basename = false) {
79 $link = "";
80 if (strlen($this->entry)) {
81 $parts = explode(DIRECTORY_SEPARATOR, $this->entry);
82 $link = $basename ? end($parts) : $this->joinLink($parts);
83 }
84 return htmlspecialchars($link);
85 }
86
87 /**
88 * Create a consolidated Path of this entry
89 * @return \mdref\Path
90 */
91 function getPath() {
92 $path = $this->path;
93 $file = $path($this->entry);
94 return $file;
95 }
96
97 private function openFile() {
98 if (!is_resource($this->file)) {
99 $file = $this->getPath();
100
101 if (!$file->isFile()) {
102 throw new \Exception("Not a file: '{$file}'");
103 }
104 if (!$this->file = fopen($file->getFullPath(".md"), "r")) {
105 throw new \Exception("Could not open {$file}");
106 }
107 }
108 }
109
110 /**
111 * Read the title of the refentry
112 * @return string
113 */
114 function readTitle() {
115 $this->openFile();
116 fseek($this->file, 1, SEEK_SET);
117 return fgets($this->file);
118 }
119
120 /**
121 * Read the description of the refentry
122 * @return string
123 */
124 function readDescription() {
125 $this->openFile();
126 fseek($this->file, 0, SEEK_SET);
127 fgets($this->file);
128 fgets($this->file);
129 return fgets($this->file);
130 }
131
132 /**
133 * Format a "Edit me" URL. The project reference top directory needs a
134 * »name«.mdref file besides its »name«.md entry point with the edit URL
135 * printf template as content. The sole printf argument is the relative
136 * path of the entry.
137 * @return string
138 */
139 function formatEditUrl() {
140 $path = $this->path;
141 $base = current(explode(DIRECTORY_SEPARATOR, $path->getPathName()));
142 $file = $path($base);
143 if ($file->isFile(".mdref")) {
144 return sprintf(file_get_contents($file->getFullPath(".mdref")),
145 $this->entry);
146 }
147 }
148
149 /**
150 * Recurse into the reference tree
151 * @param \mdref\Finder $refs
152 * @param string $pattern
153 * @param callable $cb
154 */
155 function recurse(Finder $refs, $pattern, callable $cb) {
156 $path = $refs->find($refs->getBaseUrl()->mod($this->entry));
157 foreach (new RefListing($path, $refs->glob($path, $pattern)) as $entry) {
158 /* @var $entry RefEntry */
159 $cb($entry, $pattern, function($entry, $pattern) use ($refs, $cb) {
160 $entry->recurse($refs, $pattern, $cb);
161 });
162 }
163 }
164 }