I'm using the plugin cakephp-glide in my Cakephp4 App.
I want to delete Glide cache of an image just after the image is deleted.
My plugin FileManager triggers an event 'afterDelete' when the image file is deleted :
// in FileManager.FichiersTable
public function afterDelete(Event $event, EntityInterface $entity, ArrayObject $options)
{
$fichier = new File(WWW_ROOT . $entity->url);
$fichier->delete();
$afterDeleteEvent = new Event('FileManager.Fichiers.afterDelete', $this, [
'file' => $entity
]);
$this->getEventManager()->dispatch($afterDeleteEvent);
}
and I want to catch the event in bootstrap of my application to delete the cache of the image :
//in bootstrap.php
EventManager::instance()
->on(
'FileManager.Fichiers.afterDelete',
function (Event $event) {
// Delete cache of $event->getData('file')
$filename = $event->getData('file')->filename;
$server->deleteCache($filename); // How to get the instance $server ???
}
);
But I don't know how to get the Glide Server instance ?
I can't find a method in the plugin to get it.
If someone could help me...
On ADmad advices, the solution is to store the Glide server config in Configure and then use this config both in routes for the ADmad/Glide plugin configuration and in my event listener to create a new server instance.
//in bootstrap.php
//'ADmad/Glide.server' will be used in routes to configure the plugin and in my event listener below to create a new server instance.
Configure::write('ADmad/Glide.server', [
// Path or League\Flysystem adapter instance to read images from.
// http://glide.thephpleague.com/1.0/config/source-and-cache/
'source' => WWW_ROOT,
// Path or League\Flysystem adapter instance to write cached images to.
'cache' => WWW_ROOT . 'files' . DS . 'cache',
// URL part to be omitted from source path. Defaults to "/images/"
// http://glide.thephpleague.com/1.0/config/source-and-cache/#set-a-base-url
'base_url' => '/images/',
// Response class for serving images. If unset (default) an instance of
// \ADmad\Glide\Response\PsrResponseFactory() will be used.
// http://glide.thephpleague.com/1.0/config/responses/
'response' => null,
]);
EventManager::instance()
->on(
'FileManager.Fichiers.afterDelete',
function (Event $event) {
$server = \League\Glide\ServerFactory::create(Configure::read('ADmad/Glide.server')); // Use the Glide server config above
$file = $event->getData('file');
$server->deleteCache(Configure::read('ADmad/Glide.server.base_url') . $file->url);
}
);
}
);
Related
I am making like a dropbox clone for a school project, i made an upload fuction that uploads to the local disk so it cant be accessed by everyone.
Upload Function
public function updatedUpload($upload){
$object = $this->currentTeam->objects()->make(['parent_id' => $this->object->id]);
$object->objectable()->associate(
$this->currentTeam->files()->create([
'name' => $upload->getClientOriginalName(),
'size' => $upload->getSize(),
'path' => $upload->storePublicly('files', ['disk' => 'local'])
])
);
$object->save();
$this->object = $this->object->fresh();
}
But I want to put it in an in the home.blade.
How do I make this and only the person who uploaded it can access it?
You can create a specific link for the user that can see this resource.
For example in your routes/web.php
Route::get('/private_resource',[\App\Http\Controllers\PrivateResource::class, 'getLocalResource'])
->name('get_private_resource')->middleware('auth');
Define PrivateResource controller
class PrivateResource
{
public function getLocalResource($filename){
// Get your resource, for example
$file = File::where('name', $filename)->first();
// Check whether user can access this resource
// For example
if(\Auth::id() != $file->user_id) abort(403);
return \Storage::disk('local')->download($filename);
}
}
Extra: If you want extra privacy, you can use signed route using below function.
\URL::signedRoute('get_private_resource');
And add signed middleware to your route
Route::get('/private_resource',[\App\Http\Controllers\PrivateResource::class, 'getLocalResource'])
->name('get_private_resource')->middleware('auth','signed');
We are using Doctrine 2 in our app, but due to our infrastructure, we do not have a static configuration for database connections. Instead, we have a collection of singletons in a service provider for each database we need to connect to, and we select a random database host for then when we connect.
Unfortunately, we are seeing some performance degradation in Doctrine's getRepository() function. I believe the issue is that Doctrine needs to generate its proxy classes at runtime (even in production) because we cannot figure out how to configure the CLI tools in order to create them at build time.
We are using the Laravel framework for the application.
Here's an example of our Laravel service provider which makes the repositories available for dependency injection.
<?php
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
use App\Database\Entities;
use App\Database\Repositories;
use App\Database\Constants\EntityConstants;
class DoctrineServiceProvider extends ServiceProvider
{
// Create a singleton for the Doctrine Manager. This class will handle entity manager generation.
$this->app->singleton(DoctrineManager::class, function ($app)
{
return new DoctrineManager(
$app->make(ConnectionFactory::class),
[
EntityConstants::ENTITY_CLASS_DATABASE1 => [app_path('Database/Entities/Database1')],
EntityConstants::ENTITY_CLASS_DATABASE2 => [app_path('Database/Entities/Database2')],
],
config('app.debug'),
$this->app->make(LoggerInterface::class)
);
});
// Register the first repository
$this->app->singleton(Repositories\Database1\RepositoryA1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA1::class);
});
// Register the second repository
$this->app->singleton(Repositories\Database1\RepositoryA2::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE1)
->getRepository(Entities\Database1\RepositoryA2::class);
});
// Register a repository for the second database
$this->app->singleton(Repositories\Database2\RepositoryB1::class, function ($app)
{
return $app[DoctrineManager::class]
->getEntityManager(EntityConstants::ENTITY_CLASS_DATABASE2)
->getRepository(Entities\Database2\RepositoryB1::class);
});
}
Here's the class that generates EntityManagers for Doctrine:
<?php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Connections\MasterSlaveConnection;
use Proprietary\ConnectionFactory;
class Manager
{
private $c_factory;
private $paths;
private $connections = [];
private $entity_managers = [];
public function __construct(
ConnectionFactory $cf,
array $paths
)
{
$this->c_factory = $cf;
$this->paths = $paths;
}
public function getConnection($name, $partition = false, $region = false)
{
// Get a list of servers for this database and format them for use with Doctrine
$servers = self::formatServers($name, $this->c_factory->getServers($name, true, $partition, $region));
// Generate a connection for the entity manager using the servers we have.
$connection = DriverManager::getConnection(
array_merge([
'wrapperClass' => MasterSlaveConnection::class,
'driver' => 'pdo_mysql',
], $servers)
);
return $connection;
}
public function getEntityManager($name, $partition = false, $region = false)
{
// Should these things be cached somehow at build time?
$config = Setup::createAnnotationMetadataConfiguration($this->paths[$name], false);
$config->setAutoGenerateProxyClasses(true);
// Set up the connection
$connection = $this->getConnection($name, $partition, $region);
$entity_manager = EntityManager::create($connection, $config);
return $entity_manager;
}
// Converts servers from a format provided by our proprietary code to a format Doctrine can use.
private static function formatServers($db_name, array $servers)
{
$doctrine_servers = [
'slaves' => [],
];
foreach ($servers as $server)
{
// Format for Doctrine
$server = [
'user' => $server['username'],
'password' => $server['password'],
'host' => $server['hostname'],
'dbname' => $db_name,
'charset' => 'utf8',
];
// Masters can also be used as slaves.
$doctrine_servers['slaves'][] = $server;
// Servers are ordered by which is closest, and Doctrine only allows a
// single master, so if we already set one, don't overwrite it.
if ($server['is_master'] && !isset($doctrine_servers['master']))
{
$doctrine_servers['master'] = $server;
}
}
return $doctrine_servers;
}
}
Our service classes use dependency injection to get the repository singletons defined in the service provider. When we use the singletons for the first time, Doctrine will use the entity class defined in the service provider and get the connection associated with the repository.
Is there any way we can enable the CLI tools with this configuration? Are there any other ways that we can optimize this for use in production?
Thanks.
I was able to solve the problem thanks to a suggestion from the Doctrine IRC channel. Since the CLI tools can only handle a single database, I created a doctrine-cli directory containing a base-config.php file and a subdirectory for each of the databases we use.
Here's an example file structure:
doctrine-cli/
|- database1/
| |- cli-config.php
|- database2/
| |- cli-config.php
|- base-config.php
The base-config.php file looks like this:
<?php
use Symfony\Component\Console\Helper\HelperSet;
use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper;
use App\Database\Doctrine\Manager as DoctrineManager;
use Proprietary\ConnectionFactory;
require __DIR__ . '/../bootstrap/autoload.php';
class DoctrineCLIBaseConfig
{
private $helper_set;
public function __construct($entity_constant, $entity_namespace)
{
$app = require_once __DIR__ . '/../bootstrap/app.php';
// Proprietary factory for getting our databse details
$connection_factory = new ConnectionFactory(...);
// Our class that parses the results from above and handles our Doctrine connection.
$manager = new DoctrineManager(
$connection_factory,
[$entity_constant => [app_path('Database/Entities/' . $entity_namespace)]],
false,
null,
null
);
$em = $manager->getEntityManager($entity_constant);
$this->helper_set = new HelperSet([
'db' => new ConnectionHelper($em->getConnection()),
'em' => new EntityManagerHelper($em),
]);
}
public function getHelperSet()
{
return $this->helper_set;
}
}
Here's an example cli-config.php from the database directory:
<?php
use App\Database\Constants\EntityConstants;
require __DIR__ . "/../base-config.php";
$config = new DoctrineCLIBaseConfig(
EntityConstants::ENTITY_CLASS_DATABASE1,
"database1"
);
return $config->getHelperSet();
Now, I'm able to cycle through each of the directories and run commands like so:
php ../../vendor/bin/doctrine orm:generate-proxies
For our build process, I wrote a simple shell script that cycles through the directories and runs the orm:generate-proxies command.
I'm writing my own PHP framework built on top of Symfony components as a learning exercise. I followed the tutorial found at http://symfony.com/doc/current/create_framework/index.html to create my framework.
I'd now like to wire up my routes against my controllers using annotations. I currently have the following code to setup the routing:
// Create the route collection
$routes = new RouteCollection();
$routes->add('home', new Route('/{slug}', [
'slug' => '',
'_controller' => 'Controllers\HomeController::index',
]));
// Create a context using the current request
$context = new RequestContext();
$context->fromRequest($request);
// Create the url matcher
$matcher = new UrlMatcher($routes, $context);
// Try to get a matching route for the request
$request->attributes->add($matcher->match($request->getPathInfo()));
I have come across the following class to load the annotations but I'm not sure how to use it:
https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
I'd appreciate it if someone could help.
Thanks
I've finally managed to get this working. First I changed where I included the autoload.php file to the following:
use Doctrine\Common\Annotations\AnnotationRegistry;
$loader = require __DIR__ . '/../vendor/autoload.php';
AnnotationRegistry::registerLoader([$loader, 'loadClass']);
Then I changed the routes collection bit (in the question) to:
$reader = new AnnotationReader();
$locator = new FileLocator();
$annotationLoader = new AnnotatedRouteControllerLoader($reader);
$loader = new AnnotationDirectoryLoader($locator, $annotationLoader);
$routes = $loader->load(__DIR__ . '/../Controllers'); // Path to the app's controllers
Here's the code for the AnnotatedRouteControllerLoader:
class AnnotatedRouteControllerLoader extends AnnotationClassLoader {
protected function configureRoute(Route $route, ReflectionClass $class, ReflectionMethod $method, $annot) {
$route->setDefault('_controller', $class->getName() . '::' . $method->getName());
}
}
This has been taken from https://github.com/sensiolabs/SensioFrameworkExtraBundle/blob/master/Routing/AnnotatedRouteControllerLoader.php. You may wish to modify it to support additional annotations.
I hope this helps.
I'm trying to add Dropzone Extension to my application in Yii, which allows asynchronous file uploading. http://www.yiiframework.com/extension/yii-dropzone/
The first thing i did was putting the downloaded folder called "dropzone" into my extensions folder "C:\xampp\htdocs\site\protected\extensions".
And here is my code for the action in the controller (MainController.php)
public function actionUpload()
{
$test = rand(100000, 999999); //TEST
var_dump($test);
$model = new UploadFile;
if(isset($_FILES['images'])){
$model->images = CUploadedFile::getInstancesByName('images');
$path = Yii::getPathOfAlias('webroot').'/uploads/';
//Save the images
foreach($model->images as $image)
{
$image->saveAs($path);
}
}
$this->render('upload', array('model' => $model));
}
the view (upload.php)
<?php
$this->widget('ext.dropzone.EDropzone', array(
'model' => $model,
'attribute' => 'images',
'url' => $this->createUrl('file/upload'),
'mimeTypes' => array('image/jpeg', 'image/png'),
'options' => array(),
));
?>
and the model (UploadFile.php)
<?php
class UploadFile extends CFormModel
{
public $images;
public function rules(){
return array
(
array(
"images",
'file',
'types' => 'jpg,gif,png',
),
);
}
}
When I run it I can see the Dropzone interface and I can add images dragging them or selection them from the file explorer.
It appears their respective progress bar and a success mark, but nothing appear in the directory of uploads, and any error is shown neither in the IDE (Netbeans) nor in the Chrome console.
I did some print tests and I realize that the code inside the 'actionUpload' is being executed only the first time (when it draws the view), but when its called from the dropzone widget it do nothing.
I'd really appreciate if you have a solution for this. I'd love if someone could give me a simple working example of this extension. Thanks.
As I understand, dropzone uploads files one by one, not all together. So $model->images holds only one image object. And foreach cycle fails.
I created a simple Phalcon project using Phalcon DevTools (1.2.3).
Now I want to use MongoDB for the database. How do I set this up correctly?
I came this far (see code below):
This is my config.php
<?php
return new \Phalcon\Config(array(
'database' => array(
'adapter' => 'Nosql', //Was 'Mysql', but Nosql is not supported?
'host' => 'localhost',
'username' => 'root',
'password' => '',
'dbname' => 'test',
),
'application' => array(
'controllersDir' => __DIR__ . '/../../app/controllers/',
'modelsDir' => __DIR__ . '/../../app/models/',
'viewsDir' => __DIR__ . '/../../app/views/',
'pluginsDir' => __DIR__ . '/../../app/plugins/',
'libraryDir' => __DIR__ . '/../../app/library/',
'cacheDir' => __DIR__ . '/../../app/cache/',
'baseUri' => 'localhost/',
)
));
This is my services.php
<?php
use Phalcon\DI\FactoryDefault,
Phalcon\Mvc\View,
Phalcon\Mvc\Url as UrlResolver,
//Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter, //Do I need this when I use Mongo?
Phalcon\Mvc\View\Engine\Volt as VoltEngine,
Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter,
Phalcon\Session\Adapter\Files as SessionAdapter;
/**
* The FactoryDefault Dependency Injector automatically register the right services providing a full stack framework
*/
$di = new FactoryDefault();
/**
* The URL component is used to generate all kind of urls in the application
*/
$di->set('url', function() use ($config) {
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
}, true);
/**
* Setting up the view component
*/
$di->set('view', function() use ($config) {
$view = new View();
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines(array(
'.volt' => function($view, $di) use ($config) {
$volt = new VoltEngine($view, $di);
$volt->setOptions(array(
'compiledPath' => $config->application->cacheDir,
'compiledSeparator' => '_'
));
return $volt;
},
'.phtml' => 'Phalcon\Mvc\View\Engine\Php'
));
return $view;
}, true);
/**
* Database connection is created based in the parameters defined in the configuration file
*/
$di->set('mongo', function() use ($config) {
$mongo = new Mongo();
return $mongo->selectDb($config->database->dbname);
});
/**
* If the configuration specify the use of metadata adapter use it or use memory otherwise
*/
$di->set('modelsMetadata', function() {
return new MetaDataAdapter();
});
/**
* Start the session the first time some component request the session service
*/
$di->set('session', function() {
$session = new SessionAdapter();
$session->start();
return $session;
});
I altered the standard mysql db connection to be mongo, using the documentation.
But now I have to set up my database adapter in Config, but Nosql doesn't seem to work. DevTools throws this error in the terminal when trying to create a model:
Error: Adapter Nosql is not supported
When I do put in ' Mysql' for the adapter in the config and try to create a model, this is the error I get:
Error: SQLSTATE[HY000] [2002] No such file or directory
Does it need the Mysql adapter to be set in order to use Mongo/Nosql? Or should I put in something else for the adapter/config? Any ideas?
within service.php file where you have mongo service registered
$di->set('mongo', function() {
$mongo = new Mongo();
return $mongo->selectDb("DB_NAME");
}, true);
below that put following lines of code,
$di->set('collectionManager', function(){
return new Phalcon\Mvc\Collection\Manager();
}, true);
After the above is done you need to ensure that your model is extending from \Phalcon\Mvc\Collection
E.g. Customers.php
class Customers extends \Phalcon\Mvc\Collection
{
public $name;
public $email;
}
Once above is done, you can verify if everything is working fine as follows
$robot = new Customers();
$robot->email= "abc#test.com";
$robot->name = "XYZ";
if ($robot->save() == false)
{
echo "Could not be Saved!!";
}
else
{
echo "Data Saved!!";
}
You can put above code in any Controller-Action and try.
If everything goes well, you should be able to see one document created within Customer collection within your database of MongoDB.
Refer http://docs.phalconphp.com/en/latest/reference/odm.html for more..
$di->set('mongo', function() {
$user = 'blog';
$password = 'blog';
$host = 'localhost';
$port = '27017';
$db = 'blog';
$cn = sprintf('mongodb://%s:%d/%s',$host,$port,$db);
$con = new Mongo($cn,array('username'=>$user,'password'=>$password));
return $con->selectDB($db);
}, true);
As of the latest PhalconPHP, MongoDB seems to be a supported option for cache only, not for using as a replacement for the database.
It looks there is no MongoDB adapter for the Config component, only MySQL and couple of others (text based) in the incubator (https://github.com/phalcon/incubator).
You can still use MongoDB for the ACL and your Models though, see https://github.com/phalcon/incubator/tree/master/Library/Phalcon/Acl/Adapter and http://docs.phalconphp.com/en/latest/reference/odm.html#