Symfony 1.4 save all items' froms with one action - php

I want to create thumbnails for 200+ objects with one action in Symfony 1.4. The problem is that thmbnail generation takes place on saving the form.
class AuthorForm extends BaseAuthorForm
{
public function configure()
{
/* some configs */
}
public function save($con = null)
{
/* create thmbnail from original picture */
}
}
How can I write an (batch) action to be able to save them all at once, rather than going to each item in the backend and saving?
Please note, that just $author->save(); won't work, of course.
Thanks!

You have to fetch the objects, loop through them, create the form and save. Like the following.
$authors = Doctrine_Core::getTable('Author')->findAll();
foreach($authors as $author){
$form = new AuthorForm($author);
$form->save();
}
You'll probably have memory issues if you're running it on a hosting plan (not your dev machine). A better way to get thumbnails is using a plugin like sfImageTransformExtraPlugin (http://www.symfony-project.org/plugins/sfImageTransformExtraPlugin) that generates a cached thumbnail as you need them. You don't even need to go through the trouble of generating the thumbnails. And still can have multiple thumbnail versions of the same photo pretty easily.
If you still need to use this way, do some unset stuff during the loop, like the following.
$authors = Doctrine_Core::getTable('Author')->findAll();
foreach($authors as $author){
$form = new AuthorForm($author);
$form->save();
unset($form, $author);
}

Related

Make model dynamically using user supplied model name in laravel

I am stuck with it and i couldn't find any appropriate solution for this. what i want to achieve is in my admin panel based upon check box value i want to change active status of specific control and update database value using ajax. I want to make a common ajax function in controller to avoid repeatedly writing same ajax function for other controls like menu manager content manager, documents manager etc.So i want to send Model name to the ajax controller so that same function can be used. Ajax call is working perfectly but couldn't make appropriate models. for example:
$m = new App\Model.$request->model OR $m = 'App\Model\'.$request->model (adding last \ gives an error) or answer provided in Dynamically use model in laravel is not helping either. Is there any better ways if yes please suggest. I can do this below but it is hardcoded so i want to make model dynamic models
if($request->model ==='Menu')
$model = new \App\Http\Models\Menu;
else if($request->model === 'News')
$this->model = new \App\Http\Models\News;
else if($request->model === 'Document')
$this->model = new \App\Http\Models\Document;
Thankyou !!!
You can just use:
$modelName = '\\App\\Http\\Models\\'.$request->model;
$this->model = new $modelName;
However you should add validation to make sure only some allowed models would be used or at least do something like this:
if (! in_array($request->model, ['Menu', 'News', 'Document']))
{
throw new \Exception('Invalid model');
}
$modelName = '\\App\\Http\\Models\\'.$request->model;
$this->model = new $modelName;
This is because you don't want to expose probably all the models data for security reasons.
Try the below code
if($request->model){
$m = '\App'. '\' .$request->model;
//other code
}

Get auto generated ID right after flush() Symfony3

I have a Project entity and when creating a new project I need to be able to upload files. For this reason I have created Files entity which saves the path and projectID. My problem is that I don't know how to retrieve it after creating it. Here is what I am trying to do
$projectService->createProject($project,$user,$isWithoutTerm,self::NO_TERM_DEFAULT_VALUE);
$filesService = $this->get('app.service.files_service');
foreach ($managerFiles as $managerFile){
$fileName = $filesService->uploadFileAndReturnName($managerFile);
$filesService->createFile($fileName,$project->getId(),$user);
}
Currently my $project doesn't have ID which means that I cant create a new file. I heard that I could use $em->retrieve(object), but the actual flushing is not done in the controller. If i try to use it in my createProject function and return it for some reason I can't. PHPStorm says that it is a void function. Here is the code in createProject
$project->setFromUser($user->getFullName());
$project->setDepartment($user->getDepartment());
$project->setIsOver(false);
$project->setDate(new \DateTime());
if($isWithoutTerm){
$project->setTerm(\DateTime::createFromFormat('Y-m-d', $noTermDefaultValue));
}
$this->entityManager->persist($project);
$this->entityManager->flush();
Is there a way to retrieve the projectID after flushing and being able to use it in my controller?
It could be a race condition where the $project is not available yet and so the service cannot load it and thus getId() fails.
First, create your project entity:
//build your $project
$this->entityManager->flush();
Second, send this $project to your "service"
$projectService->createProject($project,$user,$isWithoutTerm,self::NO_TERM_DEFAULT_VALUE);
$filesService = $this->get('app.service.files_service');
foreach ($managerFiles as $managerFile){
$fileName = $filesService->uploadFileAndReturnName($managerFile);
$filesService->createFile($fileName,$project->getId(),$user);
}
More specifically if you wrap this in a try/catch you can identify exactly what is happening:
try {
$project = new Project();
//build project
$this->entityManager->flush();
//load $projectService..
$projectService->createProject($project,$user,$isWithoutTerm,self::NO_TERM_DEFAULT_VALUE);
$filesService = $this->get('app.service.files_service');
foreach ($managerFiles as $managerFile){
$fileName = $filesService->uploadFileAndReturnName($managerFile);
$filesService->createFile($fileName,$project->getId(),$user);
}
}
catch(\Exception $e) {
//$e->getMessage() will tell you if you're good to go, or if there
//is actually an issue
}
However, it could also be as simple as PHPStorm not being able to introspect your getId() method and thus doesn't understand it. OR getId() is not actually returning the id.
Upgrading the Symfony from 3.2 and 3.3 fixed the issue. I don't think it was due to the version itself, but rather removing depricated stuff and changing a lot of things and something fixed it.

Doctrine (Mongo) Persisting Partial Document

I have a custom class that populates a controller's action parameters based on the typehint of the parameter. This works well for documents (using public properties and setters).
My aim is to make the controller simple:
function updateAction(Article $article)
{
$dm = new DocumentManager(); // code elsewhere
$dm->merge($article);
$dm->flush();
return $this->redirect('/article/' . $article->getId());
}
The problem is that the input supplying the fields to programatically populate the Article class doesn't contain all of the properties of an Article class (perhaps the edit form only contains Title and Content, but disregards Author, etc).
I was hoping that the presence of an ID would allow the document to be merged gracefully with what is currently in the database. However, any fields that are missing at the time of a merge will be removed from the document in the database.
Is there a way to update a document in such a way that only the fields that are present (non-null, I guess) are updated?
Rather than hitting the db twice - once for the find, and once for the update, you can use a FIND_AND_UPDATE query.and do it all in one step.
See this docs page for details: http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/find-and-update.html
It seems that a clean way would be to bind the model AFTER retrieving it from the database. Something along the lines of ASP.NET MVC's UpdateModel.
function updateAction($id)
{
$dm = new DocumentManager(); // code elsewhere
$article = $dm->getRepository('Article')->find($id);
$this->updateModel($article);
$dm->flush();
return $this->redirect('/article/' . $article->getId());
}
If there are any better suggestions, feel free to answer...

Zend cache frontend configuration

Zend_Cache can be configured to cache several types of output, including
the results of function calls, the results of object and static method calls,
entire pages, and configuration data.
Given this controller and related views how would you go with caching?From what some of you suggested here (see #marcin) I understood that clearing the whole cache for just a single comment or a post-update would be too much.How should I go for them to be cached separately?
Basically I have a blog page where I'm loading all of the posts with relative users comments.
-Index controller (home-page):
class IndexController extends Zend_Controller_Action
{
public function indexAction()
{
//Post is a db_table model
$post_manager=new Post();
$allPosts=$post_manager->getAllPosts();
$this->view->posts=$allPosts;
}
}
-index.phtml:
echo $this->partialLoop('_posts.phtml',$this->posts);
-_posts.phtml:
echo $this->object->title;
echo $this->object->text;
echo $this->partialLoop('_comments.phtml',$this->object->getComments());
-_comments.phtml:
echo $this->object->text;
Please post practical examples
thanks again
Sorry I did not replay earlier. Quickly, I'll would like to present one way of catching this for your consideration. For simplicity, I'll just concentrate on caching your outputs using Output frontend.
In you application.ini you can setup your catching as follows:
resources.cachemanager.myviewcache.frontend.name = Output
resources.cachemanager.myviewcache.frontend.customFrontendNaming = false
resources.cachemanager.myviewcache.frontend.options.lifetime = 7200
resources.cachemanager.myviewcache.frontend.options.caching = true
resources.cachemanager.myviewcache.frontend.options.automatic_serialization = true
resources.cachemanager.myviewcache.backend.name = Apc
Note, that I use Apc as a backend. You may use file backend if you don't have or don't want Apc.
With this, I would cache your posts and comments separately. For example, in _posts.phtml you could do something similar to the following:
// first cache an output related to the body of your post with key being associated
// with your post.
if (!($this->viewCache()->start('post_' . (string) $this->object->post_id))) {
echo $this->object->title;
echo $this->object->text;
}
// now I cache an output of a comments associated with a give post
if (!($this->viewCache()->start('post_comments_' . (string) $this->object->post_id))) {
echo $this->partialLoop('_comments.phtml',$this->object->getComments());
}
In this example, viewCache() view helper is as follows:
class My_View_Helper_ViewCache extends Zend_View_Helper_Abstract {
/**
*
* #return Zend_Cache_Frontend_Output
*/
public function viewCache() {
return Zend_Registry::get('outputCache');
}
}
Whereas I set outputCache into registry in the Bootstrap.php:
protected function _initPutChachesIntoRegistry() {
$this->bootstrap('cachemanager');
$cacheManager = $this->getResource('cachemanager');
Zend_Registry::set('outputCache', $cacheManager->getCache('myviewcache'));
}
Notice that caches are associated with keys which in turn relate to a given post and its comments. With this, when you get a new comment, you just reset a cache related to the given post. For example, in an action, you can remove comment cache for a post with $post_id=5 as follows:
$this->view->viewCache()->remove('post_comments_' . $post_id);
Hope that this will help you or at least give you some ideas how to make it.
I don`t know how to do better, but your can do like this:
Write plugin, that will be cache response of controller using postDispatch, and restore it if it in cache using preDispatch

Reduce database calls for php web shop

I'm looking for a way to prevent repeated calls to the database if the item in question has already been loaded previously. The reason is that we have a lot of different areas that show popular items, latest releases, top rated etc. and sometimes it happens that one item appears in multiple lists on the same page.
I wonder if it's possible to save the object instance in a static array associated with the class and then check if the data is actually in there yet, but then how do I point the new instance to the existing one?
Here's a draft of my idea:
$baseball = new Item($idOfTheBaseballItem);
$baseballAgain = new Item($idOfTheBaseballItem);
class Item
{
static $arrItems = array();
function __construct($id) {
if(in_array($id, self::arrItems)){
// Point this instance to the object in self::arrItems[$id]
// But how?
}
else {
// Call the database
self::arrItems[id] = $this;
}
}
}
If you have any other ideas or you just think I'm totally nuts, let me know.
You should know that static variables only exist in the page they were created, meaning 2 users that load the same page and get served the same script still exist as 2 different memory spaces.
You should consider caching results, take a look at code igniter database caching
What you are trying to achieve is similar to a singleton factory
$baseball = getItem($idOfTheBaseballItem);
$baseballAgain =getItem($idOfTheBaseballItem);
function getItem($id){
static $items=array();
if(!isset($items[$id])$items[$id]=new Item($id);
return $items[$id];
}
class Item{
// this stays the same
}
P.S. Also take a look at memcache. A very simple way to remove database load is to create a /cache/ directory and save database results there for a few minutes or until you deem the data old (this can be done in a number of ways, but most approaches are time based)
You can't directly replace "this" in constructor. Instead, prepare a static function like "getById($id)" that returns object from list.
And as stated above: this will work only per page load.

Categories