1<?php
2
3/*
4 * This file is part of the Prophecy.
5 * (c) Konstantin Kudryashov <ever.zet@gmail.com>
6 *     Marcello Duarte <marcello.duarte@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace Prophecy\Doubler\ClassPatch;
13
14use Prophecy\Doubler\Generator\Node\ClassNode;
15use Prophecy\Doubler\Generator\Node\MethodNode;
16
17/**
18 * SplFileInfo patch.
19 * Makes SplFileInfo and derivative classes usable with Prophecy.
20 *
21 * @author Konstantin Kudryashov <ever.zet@gmail.com>
22 */
23class SplFileInfoPatch implements ClassPatchInterface
24{
25    /**
26     * Supports everything that extends SplFileInfo.
27     *
28     * @param ClassNode $node
29     *
30     * @return bool
31     */
32    public function supports(ClassNode $node)
33    {
34        if (null === $node->getParentClass()) {
35            return false;
36        }
37        return 'SplFileInfo' === $node->getParentClass()
38            || is_subclass_of($node->getParentClass(), 'SplFileInfo')
39        ;
40    }
41
42    /**
43     * Updated constructor code to call parent one with dummy file argument.
44     *
45     * @param ClassNode $node
46     */
47    public function apply(ClassNode $node)
48    {
49        if ($node->hasMethod('__construct')) {
50            $constructor = $node->getMethod('__construct');
51        } else {
52            $constructor = new MethodNode('__construct');
53            $node->addMethod($constructor);
54        }
55
56        if ($this->nodeIsDirectoryIterator($node)) {
57            $constructor->setCode('return parent::__construct("' . __DIR__ . '");');
58
59            return;
60        }
61
62        if ($this->nodeIsSplFileObject($node)) {
63            $filePath = str_replace('\\','\\\\',__FILE__);
64            $constructor->setCode('return parent::__construct("' . $filePath .'");');
65
66            return;
67        }
68
69        if ($this->nodeIsSymfonySplFileInfo($node)) {
70            $filePath = str_replace('\\','\\\\',__FILE__);
71            $constructor->setCode('return parent::__construct("' . $filePath .'", "", "");');
72
73            return;
74        }
75
76        $constructor->useParentCode();
77    }
78
79    /**
80     * Returns patch priority, which determines when patch will be applied.
81     *
82     * @return int Priority number (higher - earlier)
83     */
84    public function getPriority()
85    {
86        return 50;
87    }
88
89    /**
90     * @param ClassNode $node
91     * @return boolean
92     */
93    private function nodeIsDirectoryIterator(ClassNode $node)
94    {
95        $parent = $node->getParentClass();
96
97        return 'DirectoryIterator' === $parent
98            || is_subclass_of($parent, 'DirectoryIterator');
99    }
100
101    /**
102     * @param ClassNode $node
103     * @return boolean
104     */
105    private function nodeIsSplFileObject(ClassNode $node)
106    {
107        $parent = $node->getParentClass();
108
109        return 'SplFileObject' === $parent
110            || is_subclass_of($parent, 'SplFileObject');
111    }
112
113    /**
114     * @param ClassNode $node
115     * @return boolean
116     */
117    private function nodeIsSymfonySplFileInfo(ClassNode $node)
118    {
119        $parent = $node->getParentClass();
120
121        return 'Symfony\\Component\\Finder\\SplFileInfo' === $parent;
122    }
123}
124