Skip to content

Commit 8ee7a2a

Browse files
committed
Release 4.0.0-beta.4
1 parent 4fc8c85 commit 8ee7a2a

File tree

128 files changed

+3277
-289
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+3277
-289
lines changed

app/Controllers/Home.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<?php namespace App\Controllers;
22

3-
use CodeIgniter\Controller;
43
use App\Models\UserModel;
54

65
class Home extends BaseController

system/Autoloader/FileLocator.php

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ public function locateFile(string $file, string $folder = null, string $ext = 'p
106106
unset($segments[0]);
107107
}
108108

109-
$path = '';
109+
$paths = [];
110110
$prefix = '';
111111
$filename = '';
112112

@@ -115,31 +115,46 @@ public function locateFile(string $file, string $folder = null, string $ext = 'p
115115

116116
while (! empty($segments))
117117
{
118-
$prefix .= empty($prefix)
119-
? ucfirst(array_shift($segments))
120-
: '\\' . ucfirst(array_shift($segments));
118+
$prefix .= empty($prefix) ? array_shift($segments) : '\\' . array_shift($segments);
121119

122120
if (empty($namespaces[$prefix]))
123121
{
124122
continue;
125123
}
126-
$path = $this->getNamespaces($prefix);
124+
$paths = $namespaces[$prefix];
127125

128126
$filename = implode('/', $segments);
129127
break;
130128
}
131-
132-
// IF we have a folder name, then the calling function
133-
// expects this file to be within that folder, like 'Views',
134-
// or 'libraries'.
135-
if (! empty($folder) && strpos($path . $filename, '/' . $folder . '/') === false)
129+
130+
// if no namespaces matched then quit
131+
if (empty($paths))
136132
{
137-
$filename = $folder . '/' . $filename;
133+
return false;
138134
}
135+
136+
// Check each path in the namespace
137+
foreach ($paths as $path)
138+
{
139+
// Ensure trailing slash
140+
$path = rtrim($path, '/') . '/';
141+
142+
// If we have a folder name, then the calling function
143+
// expects this file to be within that folder, like 'Views',
144+
// or 'libraries'.
145+
if (! empty($folder) && strpos($path . $filename, '/' . $folder . '/') === false)
146+
{
147+
$path .= trim($folder, '/') . '/';
148+
}
139149

140-
$path .= $filename;
141-
142-
return is_file($path) ? $path : false;
150+
$path .= $filename;
151+
if (is_file($path))
152+
{
153+
return $path;
154+
}
155+
}
156+
157+
return false;
143158
}
144159

145160
//--------------------------------------------------------------------
@@ -265,21 +280,10 @@ protected function ensureExt(string $path, string $ext): string
265280
/**
266281
* Return the namespace mappings we know about.
267282
*
268-
* @param string|null $prefix
269-
*
270283
* @return array|string
271284
*/
272-
protected function getNamespaces(string $prefix = null)
285+
protected function getNamespaces()
273286
{
274-
if ($prefix)
275-
{
276-
$path = $this->autoloader->getNamespace($prefix);
277-
278-
return isset($path[0])
279-
? rtrim($path[0], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR
280-
: '';
281-
}
282-
283287
$namespaces = [];
284288

285289
foreach ($this->autoloader->getNamespace() as $prefix => $paths)

system/Cache/CacheFactory.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
namespace CodeIgniter\Cache;
4040

4141
use CodeIgniter\Cache\Exceptions\CacheException;
42+
use CodeIgniter\Exceptions\CriticalError;
4243

4344
/**
4445
* Class Cache
@@ -93,7 +94,20 @@ public static function getHandler($config, string $handler = null, string $backu
9394
}
9495
}
9596

96-
$adapter->initialize();
97+
// If $adapter->initialization throws a CriticalError exception, we will attempt to
98+
// use the $backup handler, if that also fails, we resort to the dummy handler.
99+
try
100+
{
101+
$adapter->initialize();
102+
}
103+
catch (CriticalError $e)
104+
{
105+
// log the fact that an exception occurred as well what handler we are resorting to
106+
log_message('critical', $e->getMessage() . ' Resorting to using ' . $backup . ' handler.');
107+
108+
// get the next best cache handler (or dummy if the $backup also fails)
109+
$adapter = self::getHandler($config, $backup, 'dummy');
110+
}
97111

98112
return $adapter;
99113
}

system/Cache/Handlers/MemcachedHandler.php

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -115,35 +115,68 @@ public function __destruct()
115115
*/
116116
public function initialize()
117117
{
118-
if (class_exists('\Memcached'))
118+
// Try to connect to Memcache or Memcached, if an issue occurs throw a CriticalError exception,
119+
// so that the CacheFactory can attempt to initiate the next cache handler.
120+
try
119121
{
120-
$this->memcached = new \Memcached();
121-
if ($this->config['raw'])
122+
if (class_exists('\Memcached'))
122123
{
123-
$this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
124+
// Create new instance of \Memcached
125+
$this->memcached = new \Memcached();
126+
if ($this->config['raw'])
127+
{
128+
$this->memcached->setOption(\Memcached::OPT_BINARY_PROTOCOL, true);
129+
}
130+
131+
// Add server
132+
$this->memcached->addServer(
133+
$this->config['host'], $this->config['port'], $this->config['weight']
134+
);
135+
136+
// attempt to get status of servers
137+
$stats = $this->memcached->getStats();
138+
139+
// $stats should be an associate array with a key in the format of host:port.
140+
// If it doesn't have the key, we know the server is not working as expected.
141+
if( !isset($stats[$this->config['host']. ':' .$this->config['port']]) )
142+
{
143+
throw new CriticalError('Cache: Memcached connection failed.');
144+
}
124145
}
125-
}
126-
elseif (class_exists('\Memcache'))
127-
{
128-
$this->memcached = new \Memcache();
129-
}
130-
else
131-
{
132-
throw new CriticalError('Cache: Not support Memcache(d) extension.');
133-
}
146+
elseif (class_exists('\Memcache'))
147+
{
148+
// Create new instance of \Memcache
149+
$this->memcached = new \Memcache();
134150

135-
if ($this->memcached instanceof \Memcached)
151+
// Check if we can connect to the server
152+
$can_connect = $this->memcached->connect(
153+
$this->config['host'], $this->config['port']
154+
);
155+
156+
// If we can't connect, throw a CriticalError exception
157+
if($can_connect == false){
158+
throw new CriticalError('Cache: Memcache connection failed.');
159+
}
160+
161+
// Add server, third parameter is persistence and defaults to TRUE.
162+
$this->memcached->addServer(
163+
$this->config['host'], $this->config['port'], true, $this->config['weight']
164+
);
165+
}
166+
else
167+
{
168+
throw new CriticalError('Cache: Not support Memcache(d) extension.');
169+
}
170+
}
171+
catch (CriticalError $e)
136172
{
137-
$this->memcached->addServer(
138-
$this->config['host'], $this->config['port'], $this->config['weight']
139-
);
173+
// If a CriticalError exception occurs, throw it up.
174+
throw $e;
140175
}
141-
elseif ($this->memcached instanceof \Memcache)
176+
catch (\Exception $e)
142177
{
143-
// Third parameter is persistence and defaults to TRUE.
144-
$this->memcached->addServer(
145-
$this->config['host'], $this->config['port'], true, $this->config['weight']
146-
);
178+
// If an \Exception occurs, convert it into a CriticalError exception and throw it.
179+
throw new CriticalError('Cache: Memcache(d) connection refused (' . $e->getMessage() . ').');
147180
}
148181
}
149182

system/Cache/Handlers/PredisHandler.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ public function __construct($config)
9999
*/
100100
public function initialize()
101101
{
102+
// Try to connect to Redis, if an issue occurs throw a CriticalError exception,
103+
// so that the CacheFactory can attempt to initiate the next cache handler.
102104
try
103105
{
104106
// Create a new instance of Predis\Client
@@ -110,7 +112,7 @@ public function initialize()
110112
catch (\Exception $e)
111113
{
112114
// thrown if can't connect to redis server.
113-
throw new CriticalError('Cache: Predis connection refused (' . $e->getMessage() . ')');
115+
throw new CriticalError('Cache: Predis connection refused (' . $e->getMessage() . ').');
114116
}
115117
}
116118

system/Cache/Handlers/RedisHandler.php

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
namespace CodeIgniter\Cache\Handlers;
4040

4141
use CodeIgniter\Cache\CacheInterface;
42+
use CodeIgniter\Exceptions\CriticalError;
4243

4344
/**
4445
* Redis cache handler
@@ -116,19 +117,38 @@ public function initialize()
116117
$config = $this->config;
117118

118119
$this->redis = new \Redis();
119-
if (! $this->redis->connect($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout']))
120-
{
121-
log_message('error', 'Cache: Redis connection failed. Check your configuration.');
122-
}
123120

124-
if (isset($config['password']) && ! $this->redis->auth($config['password']))
121+
// Try to connect to Redis, if an issue occurs throw a CriticalError exception,
122+
// so that the CacheFactory can attempt to initiate the next cache handler.
123+
try
125124
{
126-
log_message('error', 'Cache: Redis authentication failed.');
125+
// Note:: If Redis is your primary cache choice, and it is "offline", every page load will end up been delayed by the timeout duration.
126+
// I feel like some sort of temporary flag should be set, to indicate that we think Redis is "offline", allowing us to bypass the timeout for a set period of time.
127+
128+
if (! $this->redis->connect($config['host'], ($config['host'][0] === '/' ? 0 : $config['port']), $config['timeout']))
129+
{
130+
// Note:: I'm unsure if log_message() is necessary, however I'm not 100% comfortable removing it.
131+
log_message('error', 'Cache: Redis connection failed. Check your configuration.');
132+
throw new CriticalError('Cache: Redis connection failed. Check your configuration.');
133+
}
134+
135+
if (isset($config['password']) && ! $this->redis->auth($config['password']))
136+
{
137+
log_message('error', 'Cache: Redis authentication failed.');
138+
throw new CriticalError('Cache: Redis authentication failed.');
139+
}
140+
141+
if (isset($config['database']) && ! $this->redis->select($config['database']))
142+
{
143+
log_message('error', 'Cache: Redis select database failed.');
144+
throw new CriticalError('Cache: Redis select database failed.');
145+
}
127146
}
128-
129-
if (isset($config['database']) && ! $this->redis->select($config['database']))
147+
catch (\RedisException $e)
130148
{
131-
log_message('error', 'Cache: Redis select database failed.');
149+
// $this->redis->connect() can sometimes throw a RedisException.
150+
// We need to convert the exception into a CriticalError exception and throw it.
151+
throw new CriticalError('Cache: RedisException occurred with message (' . $e->getMessage() . ').');
132152
}
133153
}
134154

system/CodeIgniter.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class CodeIgniter
6565
/**
6666
* The current version of CodeIgniter Framework
6767
*/
68-
const CI_VERSION = '4.0.0-beta.3';
68+
const CI_VERSION = '4.0.0-beta.4';
6969

7070
/**
7171
* App startup time.
@@ -642,7 +642,7 @@ public function getPerformanceStats(): array
642642
*/
643643
protected function generateCacheName($config): string
644644
{
645-
if (is_cli() && ! (ENVIRONMENT === 'testing'))
645+
if (get_class($this->request) === CLIRequest::class)
646646
{
647647
return md5($this->request->getPath());
648648
}
@@ -704,7 +704,7 @@ protected function tryToRouteIt(RouteCollectionInterface $routes = null)
704704
}
705705

706706
// $routes is defined in Config/Routes.php
707-
$this->router = Services::router($routes);
707+
$this->router = Services::router($routes, $this->request);
708708

709709
$path = $this->determinePath();
710710

@@ -985,16 +985,9 @@ public function storePreviousURL($uri)
985985
/**
986986
* Modifies the Request Object to use a different method if a POST
987987
* variable called _method is found.
988-
*
989-
* Does not work on CLI commands.
990988
*/
991989
public function spoofRequestMethod()
992990
{
993-
if (is_cli())
994-
{
995-
return;
996-
}
997-
998991
// Only works with POSTED forms
999992
if ($this->request->getMethod() !== 'post')
1000993
{

system/Commands/Database/MigrateRollback.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public function run(array $params = [])
126126
}
127127
else
128128
{
129-
// Get all namespaces form PSR4 paths.
129+
// Get all namespaces from PSR4 paths.
130130
$config = new Autoload();
131131
$namespaces = $config->psr4;
132132
foreach ($namespaces as $namespace => $path)

system/Commands/Utilities/Routes.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public function run(array $params)
109109
'get',
110110
'head',
111111
'post',
112+
'patch',
112113
'put',
113114
'delete',
114115
'options',

system/Common.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -814,6 +814,8 @@ function force_https(int $duration = 31536000, RequestInterface $request = null,
814814
// Set an HSTS header
815815
$response->setHeader('Strict-Transport-Security', 'max-age=' . $duration);
816816
$response->redirect($uri);
817+
$response->sendHeaders();
818+
817819
exit();
818820
}
819821
}

system/Config/Config.php

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,13 +122,28 @@ private static function createClass(string $name)
122122
{
123123
return new $name();
124124
}
125-
125+
126126
$locator = Services::locator();
127127
$file = $locator->locateFile($name, 'Config');
128-
128+
129129
if (empty($file))
130130
{
131-
return null;
131+
// No file found - check if the class was namespaced
132+
if (strpos($name, '\\') !== false)
133+
{
134+
// Class was namespaced and locateFile couldn't find it
135+
return null;
136+
}
137+
138+
// Check all namespaces
139+
$files = $locator->search('Config/' . $name);
140+
if (empty($files))
141+
{
142+
return null;
143+
}
144+
145+
// Get the first match (prioritizes user and framework)
146+
$file = reset($files);
132147
}
133148

134149
$name = $locator->getClassname($file);

0 commit comments

Comments
 (0)