1<?php
2
3/*
4 * This file is part of Composer.
5 *
6 * (c) Nils Adermann <naderman@naderman.de>
7 *     Jordi Boggiano <j.boggiano@seld.be>
8 *
9 * For the full copyright and license information, please view the LICENSE
10 * file that was distributed with this source code.
11 */
12
13namespace Composer\Repository\Pear;
14
15/**
16 * Read PEAR packages using REST 1.1 interface
17 *
18 * At version 1.1 package descriptions read from:
19 *  {baseUrl}/c/categories.xml
20 *  {baseUrl}/c/{category}/packagesinfo.xml
21 *
22 * @author Alexey Prilipko <palex@farpost.com>
23 */
24class ChannelRest11Reader extends BaseChannelReader
25{
26    private $dependencyReader;
27
28    public function __construct($rfs)
29    {
30        parent::__construct($rfs);
31
32        $this->dependencyReader = new PackageDependencyParser();
33    }
34
35    /**
36     * Reads package descriptions using PEAR Rest 1.1 interface
37     *
38     * @param $baseUrl  string base Url interface
39     *
40     * @return PackageInfo[]
41     */
42    public function read($baseUrl)
43    {
44        return $this->readChannelPackages($baseUrl);
45    }
46
47    /**
48     * Read list of channel categories from
49     *  {baseUrl}/c/categories.xml
50     *
51     * @param $baseUrl string
52     * @return PackageInfo[]
53     */
54    private function readChannelPackages($baseUrl)
55    {
56        $result = array();
57
58        $xml = $this->requestXml($baseUrl, "/c/categories.xml");
59        $xml->registerXPathNamespace('ns', self::ALL_CATEGORIES_NS);
60        foreach ($xml->xpath('ns:c') as $node) {
61            $categoryName = (string) $node;
62            $categoryPackages = $this->readCategoryPackages($baseUrl, $categoryName);
63            $result = array_merge($result, $categoryPackages);
64        }
65
66        return $result;
67    }
68
69    /**
70     * Read packages from
71     *  {baseUrl}/c/{category}/packagesinfo.xml
72     *
73     * @param $baseUrl      string
74     * @param $categoryName string
75     * @return PackageInfo[]
76     */
77    private function readCategoryPackages($baseUrl, $categoryName)
78    {
79        $result = array();
80
81        $categoryPath = '/c/'.urlencode($categoryName).'/packagesinfo.xml';
82        $xml = $this->requestXml($baseUrl, $categoryPath);
83        $xml->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
84        foreach ($xml->xpath('ns:pi') as $node) {
85            $packageInfo = $this->parsePackage($node);
86            $result[] = $packageInfo;
87        }
88
89        return $result;
90    }
91
92    /**
93     * Parses package node.
94     *
95     * @param $packageInfo  \SimpleXMLElement   xml element describing package
96     * @return PackageInfo
97     */
98    private function parsePackage($packageInfo)
99    {
100        $packageInfo->registerXPathNamespace('ns', self::CATEGORY_PACKAGES_INFO_NS);
101        $channelName = (string) $packageInfo->p->c;
102        $packageName = (string) $packageInfo->p->n;
103        $license = (string) $packageInfo->p->l;
104        $shortDescription = (string) $packageInfo->p->s;
105        $description = (string) $packageInfo->p->d;
106
107        $dependencies = array();
108        foreach ($packageInfo->xpath('ns:deps') as $node) {
109            $dependencyVersion = (string) $node->v;
110            $dependencyArray = unserialize((string) $node->d);
111
112            $dependencyInfo = $this->dependencyReader->buildDependencyInfo($dependencyArray);
113
114            $dependencies[$dependencyVersion] = $dependencyInfo;
115        }
116
117        $releases = array();
118        $releasesInfo = $packageInfo->xpath('ns:a/ns:r');
119        if ($releasesInfo) {
120            foreach ($releasesInfo as $node) {
121                $releaseVersion = (string) $node->v;
122                $releaseStability = (string) $node->s;
123                $releases[$releaseVersion] = new ReleaseInfo(
124                    $releaseStability,
125                    isset($dependencies[$releaseVersion]) ? $dependencies[$releaseVersion] : new DependencyInfo(array(), array())
126                );
127            }
128        }
129
130        return new PackageInfo(
131            $channelName,
132            $packageName,
133            $license,
134            $shortDescription,
135            $description,
136            $releases
137        );
138    }
139}
140