1: <?php
2: /**
3: * You may not change or alter any portion of this comment or credits
4: * of supporting developers from this source code or any supporting source code
5: * which is considered copyrighted (c) material of the original comment or credit authors.
6: * This program is distributed in the hope that it will be useful,
7: * but WITHOUT ANY WARRANTY; without even the implied warranty of
8: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
9: */
10:
11: namespace Xoops\Core\Handler;
12:
13: use Xoops\Core\Database\Connection;
14: use Xoops\Core\Exception\InvalidHandlerSpecException;
15: use Xoops\Core\Exception\NoHandlerException;
16: use Xoops\Core\Handler\Scheme\SchemeInterface;
17: use Xoops\Core\Kernel\XoopsObjectHandler;
18:
19: /**
20: * Factory to build handlers
21: *
22: * @category Xoops\Core\Handler\Factory
23: * @package Xoops\Core
24: * @author Richard Griffith <richard@geekwright.com>
25: * @copyright 2015 XOOPS Project (http://xoops.org)
26: * @license GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
27: * @link http://xoops.org
28: */
29: class Factory
30: {
31: /**
32: * @var Connection
33: */
34: private static $db;
35:
36: /**
37: * @var Factory The reference to *Singleton* instance of this class
38: */
39: private static $instance;
40:
41: private $schemes;
42:
43: /**
44: * Returns the *Singleton* instance of this class.
45: *
46: * @return Factory the singleton instance.
47: */
48: public static function getInstance()
49: {
50: if (null === static::$instance) {
51: static::$instance = new static();
52: static::$db = \Xoops::getInstance()->db();
53: }
54:
55: return static::$instance;
56: }
57:
58: /**
59: * Protected constructor to prevent creating a new instance of the
60: * *Singleton* via the `new` operator from outside of this class.
61: */
62: protected function __construct()
63: {
64: $this->schemes = [
65: 'fqn' => '\Xoops\Core\Handler\Scheme\FQN',
66: 'kernel' => '\Xoops\Core\Handler\Scheme\Kernel',
67: 'legacy' => '\Xoops\Core\Handler\Scheme\LegacyModule',
68: ];
69: }
70:
71: /**
72: * Private clone method to prevent cloning of the instance of the
73: * *Singleton* instance.
74: *
75: * @return void
76: */
77: private function __clone()
78: {
79: }
80:
81: /**
82: * Private unserialize method to prevent unserializing of the *Singleton*
83: * instance.
84: *
85: * @return void
86: */
87: private function __wakeup()
88: {
89: }
90:
91: /**
92: * creates a new object
93: *
94: * @return XoopsObjectHandler handler object
95: *
96: * @throws InvalidHandlerSpecException
97: * @throws NoHandlerException
98: */
99:
100: /**
101: * @param string $name Handler name
102: * - well known kernel handler name
103: * - FQN of handler class, PSR4 loadable
104: * - Full class name, to be located in a module namespace
105: * - legacy class file name (no extension) in module/dirname/class
106: * - a registered scheme name, i.e. scheme:classname
107: * @param string|null $dirname
108: * @param bool $optional
109: *
110: * @return XoopsObjectHandler|null
111: */
112: public function create($name, $dirname = null, $optional = false)
113: {
114: // have colon assume form of scheme:name
115: $foundColon = strpos($name, ':');
116: if ($foundColon !== false) {
117: $scheme = substr($name, 0, $foundColon);
118: $baseName = substr($name, $foundColon+1);
119: $handler = $this->newSpec()->scheme($scheme)->name($baseName)->optional($optional)->build();
120: return $handler;
121: }
122:
123: // have namespace separator, assume fully qualified name
124: $foundNS = (false !== strpos($name, '\\'));
125: if ($foundNS) {
126: $handler = $this->newSpec()->scheme('fqn')->name($name)->optional($optional)->build();
127: return $handler;
128: }
129:
130: // no dirname, assume kernel class
131: if ($dirname === null) {
132: $handler = $this->newSpec()->scheme('kernel')->name($name)->optional($optional)->build();
133: return $handler;
134: }
135:
136: // must be module handler
137: $handler = $this->newSpec()->scheme('legacy')->name($name)->dirname($dirname)->optional($optional)->build();
138: return $handler;
139: }
140:
141: /**
142: * @param string $name scheme name
143: * @param string $className fully qualified name of class that implements the scheme.
144: * this class must implement the SchemeInterface
145: */
146: public function registerScheme($name, $className)
147: {
148: $this->schemes[strtolower($name)] = $className;
149: }
150:
151: /**
152: * @return FactorySpec
153: */
154: public static function newSpec()
155: {
156: $instance = Factory::getInstance();
157: $spec = FactorySpec::getInstance($instance);
158: return $spec;
159: }
160:
161: /**
162: * @param FactorySpec $spec specification
163: * @return SchemeInterface
164: */
165: private function getSchemeObject(FactorySpec $spec)
166: {
167: $schemeName = $this->schemes[$spec->getScheme()];
168: $scheme = null;
169: if (class_exists($schemeName)) {
170: $scheme = new $schemeName;
171: }
172:
173: if (!($scheme instanceof SchemeInterface)) {
174: throw new InvalidHandlerSpecException(sprintf('Unknown scheme %s', $schemeName));
175: }
176: return $scheme;
177: }
178:
179: /**
180: * Build dispatches the appropriate scheme class to instantiate a
181: * handler based on the specification
182: *
183: * @param FactorySpec $spec specification for requested handler
184: *
185: * @return XoopsObjectHandler handler object
186: *
187: * @throws InvalidHandlerSpecException
188: * @throws NoHandlerException
189: */
190: public function build(FactorySpec $spec)
191: {
192: $scheme = $this->getSchemeObject($spec);
193: if ($scheme === null) {
194: return null;
195: }
196:
197: $handler = $scheme->build($spec);
198: return $handler;
199: }
200:
201: /**
202: * @return Connection
203: */
204: public function db()
205: {
206: return static::$db;
207: }
208: }
209: