I'm trying to upload an image using angular and vichUploaderBundle for symfony.
The idea is the following,
I have some tabs, if you click on them they'll display different forms, one of them is for file uploading.
My question is, How can I upload the image? I mean the correct way.
I have a html.twig file, with a form inside (I'm using includes of twig engine).
Suppose I have this form.html.twig
<form onsubmit="{{ path('upload-new-file') }}">
<input type="file" id="someFile"/>
<button> Upload Image </button>
</form>
Once you've selected the image, click on Upload, this will determine which URL matches with upload-new-file(routing.yml) (for example, It'll do some query to upload the file)
My main problem is that I get confused because I've been programming my forms in php (using createForm, form->isvalid, etc) and then rendering them with twig, I'm also using vichUploaderBundle.
In the situation that I've described I'm not able to do that, because I don't have the "form" to render it. ({{form(form)}}).
I'm not passing the form as parameter in the usual way (like in the symfony docs; $this->render('someTemplate.html.twig',array ('form' => $form)))
Imagine that we have a web page, with tabs, and if you click in one of the tabs, It'll display some form, one of the forms contains an upload input, you select an image and click on upload, what then? Recall that I'm using angularjs, vichuploaderbundle, symfony and Doctrine as ORM.
Thanks in advance!
twig file
{{ form_start(form, {'attr': {'novalidate': 'novalidate'} }) }}
<div class="form-group">
<label>{{"news.lbl.file"|trans}}</label>
{{form_widget(form.file)}}
<lable>{{form_errors(form.file)}}</lable>
</div>
<div class="form-group">
{{form_widget(form.submit)}}
</div>
{{ form_end(form)}}
class uploder
<?php
namespace BaseBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
abstract class Uploader
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="path", type="string", length=500,nullable=true)
*/
protected $path;
/**
* Set imageUrl
*
* #param string $path
* #return Category1
*/
public function setPath($path)
{
$this->path = $path;
return $this;
}
/**
* Get path
*
* #return string
*/
public function getPath()
{
return $this->path;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
public function getAbsolutePath()
{
return null === $this->path ? null : $this->getUploadRootDir() . '/' . $this->path;
}
public function getWebPath()
{
return null === $this->path ? null : $this->getUploadDir() . '/' . $this->path;
}
protected function getUploadRootDir($docroot="web")
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__ . "/../../../../$docroot/" . $this->getUploadDir();
}
protected abstract function getUploadDir();
/**
* #Assert\File(maxSize="6000000")
*/
protected $file;
/**
* Sets file.
*
* #param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
}
/**
* Get file.
*
* #return UploadedFile
*/
public function getFile()
{
return $this->file;
}
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile())
{
return;
}
// use the original file name here but you should
// sanitize it at least to avoid any security issues
// move takes the target directory and then the
// target filename to move to
$name = $this->getUploadDir() . "/" . time() . "-" . $this->getFile()->getClientOriginalName();
$this->getFile()->move(
$this->getUploadRootDir(), $name
);
// set the path property to the filename where you've saved the file
$this->path = $name;
// clean up the file property as you won't need it anymore
$this->file = null;
}
}
entity class
class entity extends Uploder
{
protected function getUploadDir()
{
return 'dirctory name';
}
}
and add filed path then remov path
Related
I'm creating a SPA backed by Symfony and ApiPlatform so I want to always load my main route despite the real path of the URL.
I want something like this:
/**
* {#inheritdoc}
*/
class DefaultController extends Controller
{
/**
* #Route("/*", name="homepage")
*
* #return Response
*/
public function indexAction(): Response
{
// replace this example code with whatever you need
return $this->render('default/index.html.twig');
}
}
In my intentions, also if the URL is something like /path/to/the/spa/page I want to anyway load the DefaultController::indexAction()route.
How to do this? (obviously the provided example doesn't work).
Ok, I've found the solution after an "illumination".
I remembered that there is the possibility to rewrite all URL adding or removing the trailing slash
Reading that article I saw this:
class RedirectingController extends Controller
{
/**
* #Route("/{url}", name="remove_trailing_slash",
* requirements={"url" = ".*\/$"})
*/
public function removeTrailingSlash(Request $request)
{
// ...
}
}
So, to intercept all URL despite the path, my DefaultController::indexAction() becomes this:
class DefaultController extends Controller
{
/**
* #Route("/{url}",requirements={"url"=".*"}, name="homepage")
*
* #return Response
*/
public function indexAction(): Response
{
// replace this example code with whatever you need
return $this->render('default/index.html.twig');
}
}
Now all URL are all handled by DefaultController::indexAction() despite the URL path.
I would recommend you to use symfony's event system instead.
Subscribe to either kernel.request or kernel.router events.
In case of kernel.request you have to overtake the Symfony\Component\HttpKernel\EventListener\RouterListener::onKernelRequest()
which priotiry is 32 (use 33 at least).
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class SpaSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => ['onKernelRequest', 33],
];
}
public function onKernelRequest(RequestEvent $event)
{
$request = $event->getRequest();
if (!$request->isXmlHttpRequest()) {
$html = $this->twig->render('spa.html.twig', [
'uri' => $request->getUri(),
]);
$response = new Response($html, Response::HTTP_OK);
$event->setResponse($response);
}
}
}
In case of kernel.router use priority 1 at least.
You can use the php bin/console debug:event-dispatcher command to find out which listeners are registered for events and their priorities.
I need to render an XML+XSL template in my application, and it used to work with cakePHP 3.0. I have made the switch to 3.1 recently and it has stopped working. The problem is that I was having a formatted view of my XML, while now I just get a plain string.
The migration guide says something about some changes in the RequestHandlerComponent, but nothing helpful (or maybe it's just me and I don't get the point :)).
This is my controller (it is exactly as it was with Cake3.0):
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Utility\Xml;
use Cake\Event\Event;
use Cake\Routing\Router;
use Cake\ORM\TableRegistry;
use Cake\Filesystem\Folder;
use Cake\Filesystem\File;
use Cake\Network\Email\Email;
use Cake\Core\Configure;
use Cake\I18n\Time;
/**
* Invoices Controller
*
* #property App\Model\Table\InvoicesTable $Invoices
*/
class InvoicesController extends AppController
{
public $components = [
'Browser',
'Reorder11'
];
public $helpers = [
'Multiple'
];
public $paginate = [];
public function initialize()
{
parent::initialize();
$this->loadComponent('Paginator');
$this->loadComponent('RequestHandler');
}
public function beforeFilter(Event $event)
{
parent::beforeFilter($event);
$this->Auth->allow(['demo']);
}
/*
* ... several other functions ...
*/
public function viewxml($id = null)
{
$this->viewBuilder()->layout('xml');
$invoice = $this->Invoices->myInvoice($id, $this->Auth->user('id'));
$this->RequestHandler->respondAs('xml');
$this->set('invoice', $invoice);
}
}
The xml.ctp layout, which is really simple
echo $this->fetch('content');
and the viewxml.ctp template just echoes the xml as a string.
How can I obtain the formatted XML+XSL again?
Try add: $this->response->header(['Content-type' => 'application/xml']);
I had the same error but my output was pdf
working 3.0.14 using this code:
$this->RequestHandler->respondAs("pdf");
$this->layout = 'pdf/default';
$this->view = 'pdf/report1_pdf';
for 3.1.x (this works if u save the file and open later, if you try to open it directly on browser its print the plain file content as a txt/html):
$this->viewBuilder()->layout('pdf/default');
$this->viewBuilder()->template('pdf/report1_pdf');
$this->RequestHandler->respondAs('pdf');
$this->response->header(['Content-type' => 'application/pdf']);
I'm wondering if there is a way to either pass additional parameters to the constructor (preferred) or retrieve the Request object to check the headers from within the Form constructor so that when I do a getForm in a controller, the form will be customized depending on how it is called?
I'm working on integrating AngularJs bindings and model tags into my form elements but I will need to modify how the submit button works whenever a form is called from Ajax vs being pulled into a Zend template via the framework.
Thus I would like to throw conditional parameters around where the submit button is added to the form, but I need to know if the rendered form is being viewed in zend or is being sent via an ajax call. I can detect the ajax call in the controller by looking at the request headers with isXmlHttpRequest(), but I'm not sure how to let the form know what the controller saw when it's retrieving the form with $this->getForm()
You can inject any options you like using a factory class.
use MyModule\Form\MyForm;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\ServiceManager\FactoryInterface;
class MyFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $formElementManager)
{
$serviceManager = $formElementManager->getServiceLocator();
$request = $serviceManager->get('Request');
// I would recommend assigning the data
// from the request to the options array
$options = [
'is_ajax' => $request->isXmlHttpRequest(),
];
// Although you could also pass in the request instance into the form
return new MyForm('my_form', $options, $request);
}
}
If you inject the request you will need modify MyForm::__construct.
namespace MyModule\Form;
use Zend\Form\Form;
use Zend\Http\Request as HttpRequest;
class MyForm extends Form
{
protected $request;
public function __construct($name, $options, HttpRequest $request)
{
$this->request = $request;
parent::__construct($name, $options);
}
}
Update your module.config.php to use the factory
return [
'form_elements' => [
'factories' => [
'MyModule\Form\MyForm' => 'MyModule\Form\MyFormFactory'
]
]
]
Then ensure you request the form from the service manager (in a controller factory)
$myForm = $serviceManager->get('FormElementManager')->get('MyModule\Form\MyForm');
My AbstractForm with helper functions (I just added the getRequest() to the bottom). Of course in a wider scale application I'd probably add error checking to make sure these were not called from the constructor (when the service manager would not yet be available)
namespace Application\Form;
use Zend\Form\Form as ZendForm;
use Zend\Http\Request as HttpRequest;
use Zend\Stdlib\RequestInterface as Request;
use Zend\Form\FormElementManager as ZendFormElementManager;
use Zend\ServiceManager\ServiceLocatorAwareInterface as ZendServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface as ZendServiceLocatorInterface;
use Doctrine\ORM\EntityManager as DoctrineEntityManager
class AbstractForm extends ZendForm implements ZendServiceLocatorAwareInterface {
/**
* #var Request
*/
protected $request;
/**
* in form context this turns out to be Zend\Form\FormElementManager
*
* #var ZendFormElementManager $service_manager
*/
protected static $service_manager;
/**
* #var DoctrineEntityManager $entity_manager
*/
protected $entity_manager;
/**
* #var ZendServiceLocatorInterface $service_locator_interface
*/
protected $service_locator_interface;
public function __construct($name = null)
{
parent::__construct($name);
}
/**
* in form context this turns out to be Zend\Form\FormElementManager
*
* #param ZendFormElementManager $serviceLocator
*/
public function setServiceLocator(FormElementManager $serviceLocator)
{
self::$service_manager = $serviceLocator;
}
/**
* in form context this turns out to be Zend\Form\FormElementManager
*
* #return ZendFormElementManager
*/
public function getServiceLocator()
{
return self::$service_manager;
}
/**
* wrapper for getServiceLocator
* #return ZendFormElementManager
*/
protected function getFormElementManager() {
return $this->getServiceLocator();
}
/**
* this returns an actual service aware interface
*
* #return ZendServiceLocatorInterface
*/
protected function getServiceManager() {
if(!($this->service_locator_interface instanceof ZendServiceLocatorInterface)) {
$this->service_locator_interface = $this->getFormElementManager()->getServiceLocator();
}
return $this->service_locator_interface;
}
/**
* #return DoctrineEntityManager
*/
protected function getEntityManager() {
if(!($this->entity_manager instanceof \DoctrineEntityManager)) {
$this->entity_manager = $this->getServiceLocator()->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->entity_manager;
}
/**
* Get request object
*
* #return Request
*/
public function getRequest()
{
if (!$this->request) {
$this->request = $this->getServiceManager()->get('Request');
}
return $this->request;
}
}
Hello i am trying to implement a helper extends the Html helper.
I created based on the documentation the below empty custom helper
<?php
namespace App\View\Helper;
use Cake\View\Helper;
use Cake\View\Helper\HtmlHelper;
use Cake\View\View;
/**
* MyHtml helper
*/
class MyHtmlHelper extends HtmlHelper
{
public function __construct(View $view, $config = []) {
parent::__construct($view, $config);
}
/**
* Default configuration.
*
* #var array
*/
protected $_defaultConfig = [];
}
I load both of them on AppController but when i use them on the view I receive the expected result from Html helper but not from custom helper why ? (the second helper doesn't return an error but just an empty result)
<?php echo $this->Html->tag('div','oti na einai2'); ?>
<?php echo $this->MyHtml->tag('div','oti na einai'); ?>
You broke it by overriding the parents default settings.
protected $_defaultConfig = [];
See the API documentation.
Merge whatever you need in the constructor for example instead of overriding the whole property with an empty array.
I want all Cakephp urls to use a subdomain if it is present in the users session... so if there is an entry 'subdomain:user' in the session of the user all pages will have 'user' as a prefix: Eg user.example.com, user.example.com/settings.
Is there an easy way to do this?
thanks,
kSeudo
There are custom route classes you could use. Create a file in APP/Lib/Route called UserSubdomainRoute.php and put this in it.
<?php
App::uses('AuthComponent', 'Controller/Component');
class UserSubdomainRoute extends CakeRoute {
/**
* #var CakeRequest
*/
private $Request;
/**
* Length of domain's TLD
*
* #var int
*/
public static $_tldLength = 1;
public function __construct($template, $defaults = array(), $options = array()) {
parent::__construct($template, $defaults, $options);
$this->Request = new CakeRequest();
$this->options = array_merge(array('protocol' => 'http'), $options);
}
/**
* Sets tld length
*
* #param $length
* #return mixed void|int
*/
public static function tldLength($length = null) {
if (is_null($length)) {
return self::$_tldLength;
}
self::$_tldLength = $length;
}
/**
* Writes out full url with protocol and subdomain
*
* #param $params
* #return string
*/
protected function _writeUrl($params) {
$protocol = $this->options['protocol'];
$subdomain = AuthComponent::user('subdomain');
if (empty($subdomain)) {
$subdomain = 'www';
}
$domain = $this->_getDomain();
$url = parent::_writeUrl($params);
return "{$protocol}://{$subdomain}.{$domain}{$url}";
}
/**
* Get domain name
*
* #return string
*/
protected function _getDomain() {
return $this->Request->domain(self::$_tldLength);
}
}
One improvement to the class would probably be to make the $Request static.
Unfortunately in Cake 2.0 there is no way to set a defaultRotueClass, however, I added that feature in 2.1+ and I don't want to tell you to upgrade so you are going to have to manually specify it for all your routes in the third param like so:
Router::connect(..., ..., array('routeClass' => 'UserSubdomainRoute');
Be sure to add at the top of routes.php
App::uses('UserSubdomainRoute', 'Lib/Route');
If you do upgrade to 2.1+ you can just add this at the top of your routes.php
Router::defaultRouteClass('UserSubdomainRoute');
Then any routs specified after will use that route class.
The main part of the route class is the _writeUrl method. It checks to see if there is a subdomain key set in the session otherwise uses www and builds the full url to return.
Heads Up: Haven't tested the class, still at school just wanted to give you a jump start. It's just a modifed version of my SubdomainRoute which works a bit differently (it used to only match routes to when a certain subdomain is set, for ex in my app matches clients subdomain to my ClientsAdminPanel plugin. You can grab that here: http://bin.cakephp.org/view/50699397 So you can see how that's done as well if you need a combination of UserSubdomainRoute and my SubdomainRoute (in the link).
Hope this helps for now. Let me know if there are any problems.
Edit:
Here's how to force a redirection - something tells me there's a better way. I'll update if I can think of it.
public function beforeFilter() {
$subdomains = $this->request->subdomains();
$subdomain = $this->Auth->user('subdomain');
if (!empty($subdomain) && !in_array($subdomain, $subdomains)) {
$this->redirect('http://' . $subdomain . '.site.com' . $this->request->here);
}
}
well if you wish to do it for all your links probably you use the same way to show all your url on your site, do you use something like $this->html->link('/blah/asd/','blah'); ?
IN Cake/Routing/Route
class SubdomainRoute extends CakeRoute {
public function match($params) {
$subdomain = isset($params['subdomain']) ? $params['subdomain'] : null;
unset($params['subdomain']);
$path = parent::match($params);
if ($subdomain) {
$path = 'http://' . $subdomain . '.localhost' . $path;
}
return $path;
}
}
When creating links you could do the following to make links pointing at other subdomains.
echo $this->Html->link(
'Other domain',
array('subdomain' => 'test', 'controller' => 'posts', 'action' => 'add')
);