nette/database

It can't access files that should have been created

Closed this issue · 6 comments

Version: dev-master

Bug Description

It throws failed to open stream: No such file or directory in \database-explorer\vendor\nette\caching\src\Caching\Storages\FileStorage.php on 137 line. It creates a _Nette.Database.Structure.0f6c8930e1b455996fff524bc1a51b4b folder and a _07414f4e15ca943e6cde032dec85d92f file inside that folder. But for some reason, it doesn't create the other folder and file and tries to access it afterwards.

Steps To Reproduce

The only think I've done was to create the following index.php file.

<?php
include('vendor/autoload.php');

use Nette\Database\Connection;

$tempDir = "./cache/database-explorer";
$storage = new Nette\Caching\Storages\FileStorage($tempDir);
$connection = new Nette\Database\Connection("pgsql:host=localhost;dbname=DBNAME;options='--client_encoding=utf8'", "postgres", "PASSWORD");


$structure = new Nette\Database\Structure($connection, $storage);
$conventions = new Nette\Database\Conventions\DiscoveredConventions($structure);
$context = new Nette\Database\Context($connection, $structure, $conventions, $storage);

$rows = $context->table('notifications');
foreach ($rows as $row) {
	echo $row->timestamp;
}

Expected Behavior

No errors.

Possible Solution

Only evaluating the library. I really like the simplicity of the idea behind it. Congrats to the developers that came up with it.

So, exactly 2 years later I came back to give it another try and the same error occurs. Different PC, PHP version, but same error. Is this project maintained yet?

Changing FileStorage.php:137 to:

$handle = @fopen($cacheFile, 'c+b'); // added '@'

makes the error go away, but I guess we lose the cache.

am also receiving the same error, and the only way I can suppress the error is by turning off the E_WARNING every time I use the explore functionality which I personally think it's a bad idea, is there a workaround to suppress the error without hiding all warnings and or without losing the cache, here is my implementation

<?php

use Nette\Database\Explorer;
use Nette\Database\Structure;
use Nette\Database\Connection;
use Nette\Caching\Storages\FileStorage;
use Nette\Database\Conventions\DiscoveredConventions;

class DB{

    private $storage;
    private $structure;
    private $conventions;

    function __construct(){
        $this->storage = new FileStorage('cache/db');
        $this->structure = new Structure($this->conn(), $this->storage);
        $this->conventions = new DiscoveredConventions($this->structure);
    }

    function conn(){
        $engine = config('db_engine');

        switch ($engine):
            
            case 'mysql':
                $hostname = config('db_host');
                $username = config('db_user');
                $password = config('db_pass');
                $database = config('db_name');

                $connector = "mysql:host=$hostname;dbname=$database";
            
                return new Connection(
                    $connector, $username, $password
                ); break;

        endswitch;
    }

    function explore(){
        error_reporting(E_ALL & ~E_WARNING);
        return new Explorer($this->conn(), $this->structure, $this->conventions, $this->storage);
    }


}
dg commented

Couldn't the problem be the use of relative path? I.e. use for example FileStorage(__DIR__ . '/cache/db')

Couldn't the problem be the use of relative path? I.e. use for example FileStorage(__DIR__ . '/cache/db')

I don't think that's the case because

  • with FileStorage(__DIR__ . '/cache/db') the error is Directory '/myRoot/project\core/cache/db' not found and the error occurs from the constructor, and this is because the cache folder is on the project basepath and DIR is relative to the execution file meanwhile cache folder is at '/myRoot/project\cache/db
public function __construct(string $dir, ?Journal $journal = null)
    {
        if (!is_dir($dir)) {
            throw new Nette\DirectoryNotFoundException("Directory '$dir' not found.");  # <<< error is thrown on this line
        }
 
        $this->dir = $dir;
        $this->journal = $journal;
 
        if (mt_rand() / mt_getrandmax() < static::$gcProbability) {
            $this->clean([]);
        }
    }
  • with FileStorage('cache/db'); everything works fine, the cache folders and files are also created successfully, the error occurs while trying to lock the cache file fopen(cache/db/_Nette.Database.cacheCode/_cacheRef): Failed to open stream: No such file or directory
public function lock(string $key): void
{
    $cacheFile = $this->getCacheFile($key);
    if (!is_dir($dir = dirname($cacheFile))) {
	    @mkdir($dir); // @ - directory may already exist
    }
    
    $handle = fopen($cacheFile, 'c+b');     # <<< error happens here
    if (!$handle) {
	    return;
    }
    
    $this->locks[$key] = $handle;
    flock($handle, LOCK_EX);
}

I used FileStorage(getcwd().'/cache/db'); everything works fine now, it also seems to be working fine with absolute path
thanks @dg