• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Cecilapp / Cecil / 16580139702

28 Jul 2025 08:57PM UTC coverage: 81.813% (-0.02%) from 81.83%
16580139702

push

github

ArnaudLigny
feat: use base path if exists

1 of 2 new or added lines in 1 file covered. (50.0%)

3140 of 3838 relevant lines covered (81.81%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.21
/src/Url.php
1
<?php
2

3
/**
4
 * This file is part of Cecil.
5
 *
6
 * (c) Arnaud Ligny <arnaud@ligny.fr>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11

12
declare(strict_types=1);
13

14
namespace Cecil;
15

16
use Cecil\Assets\Asset;
17
use Cecil\Builder;
18
use Cecil\Collection\Menu\Entry as MenuEntry;
19
use Cecil\Collection\Page\Page;
20
use Cecil\Config;
21
use Cecil\Renderer\Page as PageRenderer;
22
use Cecil\Util;
23
use Cocur\Slugify\Slugify;
24

25
/**
26
 * URL class.
27
 *
28
 * Builds an URL from a Page, a Menu Entry, an Asset or a string.
29
 */
30
class Url
31
{
32
    /** @var Builder */
33
    protected $builder;
34

35
    /** @var Config */
36
    protected $config;
37

38
    /** @var string */
39
    protected $url;
40

41
    /** @var Page Slugifier */
42
    private static $slugifier;
43

44
    /**
45
     * Creates an URL from a Page, a Menu Entry, an Asset or a string.
46
     *
47
     * @param Builder                          $builder
48
     * @param Page|MenuEntry|Asset|string|null $value
49
     * @param array|null                       $options Rendering options, e.g.: ['canonical' => true, 'format' => 'html', 'language' => 'fr']
50
     */
51
    public function __construct(Builder $builder, $value, ?array $options = null)
52
    {
53
        $this->builder = $builder;
1✔
54
        $this->config = $builder->getConfig();
1✔
55
        if (!self::$slugifier instanceof Slugify) {
1✔
56
            self::$slugifier = Slugify::create(['regexp' => Page::SLUGIFY_PATTERN]);
1✔
57
        }
58

59
        // handles options
60
        $canonical = null; // if true prefix url with baseurl config
1✔
61
        $format = null;    // output format
1✔
62
        $language = null;  // force language
1✔
63
        extract(\is_array($options) ? $options : [], EXTR_IF_EXISTS);
1✔
64

65
        // base URL
66
        $base = '';
1✔
67
        // enable canonical URL
68
        if ($this->config->isEnabled('canonicalurl') || $canonical === true) {
1✔
69
            $base = rtrim((string) $this->config->get('baseurl'), '/');
1✔
70
        }
71
        // disable canonical URL by option
72
        if ($canonical === false) {
1✔
73
            $base = '';
1✔
74
        }
75
        // use base path if exists
76
        if ($base == '' && $basepath = trim(parse_url((string) $this->config->get('baseurl'), PHP_URL_PATH), '/')) {
1✔
NEW
77
            $base = $basepath;
×
78
        }
79

80
        // if value is empty (i.e.: `url()`) returns home URL
81
        if (\is_null($value) || empty($value) || $value == '/') {
1✔
82
            $this->url = $base . '/';
1✔
83

84
            return;
1✔
85
        }
86

87
        switch (true) {
88
            case $value instanceof Page: // $value is a Page
1✔
89
                /** @var Page $value */
90
                if (!$format) {
1✔
91
                    $format = $value->getVariable('output');
1✔
92
                    if (\is_array($value->getVariable('output'))) {
1✔
93
                        $default = array_search('html', $value->getVariable('output')) ?: 0;
1✔
94
                        $format = $value->getVariable('output')[$default];
1✔
95
                    }
96
                    if (!$format) {
1✔
97
                        $format = 'html';
1✔
98
                    }
99
                }
100
                $this->url = $base . '/' . ltrim((new PageRenderer($this->config))->getPublicFilePath($value, $format), '/');
1✔
101
                if ($canonical && $value->hasVariable('canonical') && $value->getVariable('canonical')['url']) { // canonical URL
1✔
102
                    $this->url = $value->getVariable('canonical')['url'];
×
103
                }
104
                break;
1✔
105
            case $value instanceof MenuEntry: // $value is a Menu Entry
1✔
106
                /** @var MenuEntry $value */
107
                if (Util\File::isRemote($value['url'])) {
×
108
                    $this->url = $value['url'];
×
109
                    break;
×
110
                }
111
                $this->url = $base . '/' . ltrim($value['url'], '/');
×
112
                break;
×
113
            case $value instanceof Asset: // $value is an Asset
1✔
114
                /** @var Asset $value */
115
                $this->url = $base . '/' . ltrim($value['path'], '/');
1✔
116
                if ($value->isImageInCdn()) {
1✔
117
                    $this->url = (string) $value;
×
118
                }
119
                break;
1✔
120
            case \is_string($value): // others cases
1✔
121
                /** @var string $value */
122
                // $value is a potential Page ID
123
                $pageId = self::$slugifier->slugify($value);
1✔
124
                // should force language?
125
                $lang = '';
1✔
126
                if ($language !== null && $language != $this->config->getLanguageDefault()) {
1✔
127
                    $pageId = "$language/$pageId";
1✔
128
                    $lang = "$language/";
1✔
129
                }
130
                switch (true) {
131
                    case Util\File::isRemote($value): // $value is an external URL
1✔
132
                        $this->url = $value;
1✔
133
                        break;
1✔
134
                    case $this->builder->getPages()->has($pageId): // $pageId exists in pages collection
1✔
135
                        $this->url = (string) new self($this->builder, $this->builder->getPages()->get($pageId), $options);
1✔
136
                        break;
1✔
137
                    default:
138
                        // remove double language prefix
139
                        if ($lang && Util\Str::startsWith($value, $lang)) {
1✔
140
                            $value = substr($value, \strlen($lang));
1✔
141
                        }
142
                        $this->url = $base . '/' . $lang . ltrim($value, '/');
1✔
143
                }
144
        }
145
    }
146

147
    /**
148
     * If called like a string returns built URL.
149
     */
150
    public function __toString(): string
151
    {
152
        return $this->getUrl();
1✔
153
    }
154

155
    /**
156
     * Returns built URL.
157
     */
158
    public function getUrl(): string
159
    {
160
        return (string) $this->url;
1✔
161
    }
162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc