MultiUpload, jaký add-on nebo třídu použít?
- Joacim
- Člen | 229
Zdravím,
chtěl bych se zeptat zda-li používáte nějakou svoji třídu pro hromadné nahrávání souborů (fotek) a nebo používáte některý z addonů, ať již z nette nebo z jiných zdrojů.
Potřebuji multiupload pro fotky (pouze fotky) s tím, že je chci uložit vždy na jedno dané místo a data nahraji do DB (název, velikost, umístění, thumb, popisky, typ souboru), mohly by jste se prosím semnou podělit o zkušenosti, abych to nemusel celé psát od znova ? Nejlépe aby po načtení (ne nahrání) bylo možné přidat popisky ke každému souboru a až poté uložit jak fyzicky na server tak i info do DB. Pročítal jsem forum, ale moc rozumný s toho nejsem. Mám zprovozněnou svoji starou verzi, ale ta není čistě pro nette a ani MVC. Proto by mě zajímalo jak nejlépe něco takového implementovat pro nette. Mám nette 2.2.
Pro dané galerie potřebuji vytvářet i složky které budou mít jméno, ale název bude podle ID z DB
Multiupload Video
Koukal jsem na toto video, ale nevím jaký addon a ani jak jej implementovat a
navíc tam nejde přidávat po načtení žádné popisky(možná až po
nahrání souboru na server).
- Oli
- Člen | 1215
bylo možné přidat popisky ke každému souboru a až poté uložit jak fyzicky na server tak i info do DB
Tohle IMHO moc dobře nejde. Jelikož máš multiupload, tak potřebuješ nahrát fotku a potom k ní přidat popisek. Nebo naopak vytvořit popisek a k němu přiřadit fotku. Nevím o tom, že by šlo nějakým způsobem nahrát fotky (které se ve skutečnosti nenahrají), ke každé konkrétní fotce nastavit popisek a pak poslat na server naráz. Ale třeba to jde nějak jednoduše, jen o tom nevím.
Já to dělám tak, že pomocí nějakýho multiuploadu nahraju fotky na server a uložím si základní info k nim do databáze. Potom je možný si k jednotlivým fotkám doplnit informace, které jsou potřeba.
Nejpoužívanější je asi MultiFileUpload od Honzy Kuchaře. To mě ale nevyhovuje, protože to pracuje s databází.
Pokud by jsi chtěl nějakou low level knihovnu pro práci s uploadem, tak můžeš vyzkoušet můj DropzoneUploader. Teprve ho začínám používat, takže to není odladěný, ale zatím mě to funguje. Jde hlavně o to, že to uloží fotky na server a v události si zpracuješ uložení do databáze jak potřebuješ:
protected function createComponentDropzone($name)
{
$dropzone = $this->dropzone->create();
$dropzone->onSuccess[] = function (\Oli\Form\DropzoneUploader $dropzone, $targetPath, $name) {
// save to db
};
return $dropzone;
}
A pak je tu ještě knihovna, která řeší asi všechno :-) https://github.com/…istry-Images
- Oli
- Člen | 1215
Na vytváření nic nemá, mkdir je dostačující. Má jen na hledání souborů a složek https://doc.nette.org/cs/utils/finder
- Oli
- Člen | 1215
To jsou 2 věci. Pro vytvoření chceš wwwDir
, ale pro
vykreslení fotky basePath
. BasePath je už v šabloně defaultně
jako {$basePath}
. wwwDir máš v configu. Odpověď na to máš
víceméně tady: https://forum.nette.org/…-nebo-appdir#…
- Joacim
- Člen | 229
Ok, třídu ImageStorage mám jako model.
V config.neon mám:
services:
securityManager: App\Model\SecurityManager
router: App\RouterFactory::createRouter
authorizatorFactory: App\Model\AuthorizatorFactory
authorizator: @authorizatorFactory::create
imageStorage: App\Model\ImageStorage(%wwwDir%/img_gallery)
a v prezenteru, kde potřebuji použít ukládání:
namespace App\Presenters;
use Nette;
use App\Model;
use App\Model\ImageStorage;
class GalleryPresenter extends ProtectedPresenter {
/** @var Nette\Database\Context */
private $database;
/** @var ImageStorage */
private $imageStorage;
public function __construct(Nette\Database\Context $database) {
$this->database = $database;
}
public function renderDefault() {
$this->template->all_galleries = $this->database->query('select * from gallery;')->fetchAll();
$this->template->gallery_cnt = count($this->template->all_galleries);
if ($this->isAjax()) { // Pokud se jedná o ajax, přerenderujeme galleryList
$this->redrawControl('galleryList');
}
}
public function handleRenderGalleryAdd(array $gallery_data) {
if ($this->isAjax()) {
// Vrať Last ID a vytvoř novou složku podle právě přidané galerie
$lastId = $insert->id;
$new_gallery_folder = $this->context->httpRequest->url->basePath . 'img_gallery/' . $lastId . '/';
// Create gallery folder
$file = new Nette\Utils\FileSystem();
$file->createDir($new_gallery_folder); // Zde to vytvoří folder ne do www/img_gallery ale do c:\mvc\www\img_gallery\7\
}
}
public function injectImages(ImageStorage $storage) {
$this->imageStorage = $storage;
}
}
a hláška:
Nette\DI\ServiceCreationException
Service of type App\Model\ImageStorage needed by App\Presenters\GalleryPresenter::injectImages() not found. Did you register it in configuration file?
Editoval Joacim (2. 8. 2015 11:01)
- Oli
- Člen | 1215
A kam jsi dal tu třídu ImageStorage
? Někam do
app
nebo její podsložky? Pokud jo, tak to je divný. Zkus ještě
smazat cache. Pokud ne, tak na ni RobotLoader nevidí a musíš ji přesunout
někam, kde vidí.
Ještě jedna drobnost: měl by jsi vytvářet složky a soubory na cestě
wwwDir/neco
. BasePath používej jen pro vypsání. Jde o to, že
wwwDir je cesta ve file systemu k souboru, kdežto basePath je url adresa. Pro
ukládání chceš file system cestu, ale při zobrazení na stránce url
adresu.
- Joacim
- Člen | 229
Soubor se jmenuje stejně jako třída, pracuju v PHP Stormu a nebo v NetBeans, taky jsem si to 3* kontroloval, je ještě jiný způsob jak dostat cestu file systému nebo relativní cestu která mě bude fungovat jak na localhostu s WIN tak i na serveru s linuxem? třeba jen registrací cesty v config neon, jelikož nevím kde mám chybu
Nette\DI\ServiceCreationException
Service of type App\Model\ImageStorage needed by App\Presenters\GalleryPresenter::injectImages() not found. Did you register it in configuration file?
Editoval Joacim (2. 8. 2015 11:40)
- Joacim
- Člen | 229
Už jsem to zprovoznil
public function injectImages(\App\Model\ImageStorage $storage) {
$this->imageStorage = $storage;
}
a
services:
securityManager: App\Model\SecurityManager
imageStorage: App\Model\ImageStorage(%wwwDir%\img_gallery\)
router: App\RouterFactory::createRouter
authorizatorFactory: App\Model\AuthorizatorFactory
authorizator: @authorizatorFactory::create
ale pokud použiji
$new_gallery_folder = $this->imageStorage . $lastId;
// Create gallery folder
$file = new Nette\Utils\FileSystem();
$file->createDir($new_gallery_folder);
dostanu
Object of class App\Model\ImageStorage could not be converted to string
navíc, by mě zajímalo jak se to bude chovat pod linuxem když používá obrácená lomítka pro cesty
- Joacim
- Člen | 229
Použití createDir funguje spolehlivě jak na Win, tak na Linuxu
Tak jsem si stáhnul MultipleFileUpload přes composer, zaregistroval atd:.
Byl by někdo tak hodný a poradil mi jak postupovat nejlépe dál, zda li doinstalovat nějaký template pro lepší zobrazení atd:. nebo je nejjednodušší postupovat podle Ukázky ptám se proto, jelikož je to staré již přes rok a nevím zda li tu někdo nevykoumal něco lepšího
Editoval Joacim (4. 8. 2015 18:37)
- Joacim
- Člen | 229
Přidal jsem si jkuchar/MultipleFileUpload a dle Ukázky jsem si
přidal některé fce:
add.latte
{block content}
<div class="row">
<div class="col-sm-12">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-lg-12">
<h1 class="page-header">
Galerie
<small>Seznam galerií</small>
</h1>
<ol class="breadcrumb">
<li>
<i class="fa fa-photo"></i> Galerie
</li>
<li class="active">
<i class="fa fa-plus"></i> Přidání
</li>
</ol>
</div>
</div>
<!-- /.row -->
{form $form}
<ul class=error n:if="$form->errors">
<li n:foreach="$form->errors as $error">{$error}</li>
</ul>
<table>
<tr n:foreach="$form->controls as $input" n:class="$input->required ? required">
<th>{if $input->controlPrototype->type !== checkbox}{label $input /}{/if}</th>
<td>{input $input} {if $input->controlPrototype->type === checkbox}{label $input /}{/if}
<span class=error n:if="$input->errors">{$input->errors|implode:' '}</span>
</td>
</tr>
</table>
{/form}
</div>
</div>
</div>
{/block}
{block scripts}
{include parent}
<script src="{$basePath}/js/jquery-ui.min.js"></script>
<script src="{$basePath}/js/jquery.quicksearch.js"></script>
{/block}
{block head}
<link rel="stylesheet" href="{$basePath}/css/jquery-ui.min.css">
<link rel="stylesheet" href="{$basePath}/css/jquery-ui.structure.min.css">
<link rel="stylesheet" href="{$basePath}/css/jquery-ui.theme.min.css">
{/block}
GalleryPresenter.php
namespace App\Presenters;
use Nette;
use App\Model;
use App\Model\ImageStorage;
use Nette\Application\UI\Form;
/**
* Description of GalleryPresenter
*
* @author
*/
class GalleryPresenter extends ProtectedPresenter {
/** @var Nette\Database\Context */
private $database;
/** @var ImageStorage */
private $imageStorage;
public function __construct(Nette\Database\Context $database) {
$this->database = $database;
}
public function renderDefault() {
if ($this->isAjax()) { // Pokud se jedná o ajax, přerenderujeme galleryList
}
}
public function handleRenderGalleryAdd(array $gallery_data) {
if ($this->isAjax()) {
// Insert new gallery to DB
// Vrať Last ID a vytvoř novou složku podle právě přidané galerie
// Create gallery folder
}
}
public function handleRenderGalleryDelete(array $gallery_data) {
if ($this->isAjax()) {
}
}
public function injectImages(\App\Model\ImageStorage $storage) {
}
public function renderShow($gid) {
}
/**
* Returns array of suggestions
*/
public function checkConfiguration() {
$www = $this->context->expand("%wwwDir%");
$publicMFUDir = $www . "/MultipleFileUpload/";
$jsDir = $www . "/js/";
$messages = array();
if (!file_exists($publicMFUDir)) {
$messages[] = "Directory \"www/MultipleFileUpload\" not found! Copy or link content of \"libs/jkuchar/MultipleFileUpload/public\" folder to \"www/MultipleFileUpload\".";
};
if (!file_exists($publicMFUDir . "MFUFallbackController.js")) {
$messages[] = "File MFUFallbackController.js is missing! Is should be in www/MultipleFileUpload. MFU can't work without this file.";
};
if (!file_exists($jsDir)) {
$messages[] = "WARNING: Directory \"www/js\" not found! (trying to check, if jQuery is properly installed)";
}
if (!file_exists($jsDir . "jquery.js")) {
$messages[] = "WARNING: File jquery.js not found! MultipleFileUpload does not work corectly without jQuery.";
}
if (!file_exists($jsDir . "nette.ajax.js")) {
$messages[] = "WARNING: File nette.ajax.js not found! This is needed if you want to use AJAX. (https://componette.org/search/?q=vojtech-dobes%2Fnette-ajax-js)";
}
if (!file_exists($jsDir . "netteForms.js")) {
$messages[] = "WARNING: File netteForms.js not found! This is needed if you want validation of forms.";
}
return $messages;
}
public function createComponentForm($name) {
$form = new Form($this, $name);
$form->getElementPrototype()->class[] = "ajax"; // activate AJAX in https://componette.org/search/?q=vojtech-dobes%2Fnette-ajax-js
$form->addText("textField", "Text field")
->addRule(Form::FILLED, "This is required text field.");
$form->addMultipleFileUpload("upload", "Attachments");
//->addRule('MultipleFileUpload\MultipleFileUpload::validateFilled',"You have to upload at least one file!")
//->addRule('MultipleFileUpload\MultipleFileUpload::validateFileSize',"Files are together too large.",100*1024);
//$form->addMultipleFileUpload("upload2","Second file uploader");
$form->addSubmit("send", "Submit your form!");
$form->onSuccess[] = $this->handleFormSuccess;
// Invalidace snippetů
$form->onError[] = array($this, "handleRedrawForm");
$form->onSuccess[] = array($this, "handleRedrawForm");
}
public function handleFormSuccess(Form $form) {
$data = $form->getValues();
// Let's pass our data to template
$this->template->values = $data;
$queueId = uniqid();
// Moving uploaded files
foreach ($data["upload"] AS $file) {
// $file je instance HttpUploadedFile
$newFilePath = \Nette\Environment::expand("%appDir%") . "/../uploadedFilesDemo/q{" . $queueId . "}__f{" . rand(10, 99) . "}__" . $file->getName();
// V produkčním módu nepřesunujeme soubory...
if (!\Nette\Environment::isProduction()) {
if ($file->move($newFilePath))
$this->flashMessage("File " . $file->getName() . " was successfully moved!");
else
$this->flashMessage("Error while moving file " . $file->getName() . ".");
}
}
}
public function handleRedrawForm() {
// This invalidates snippet
// on AJAX requests this causes redrawing of the form
$this->invalidateControl("form");
}
public function renderAdd($gid) {
}
}
s tím že pokud se dostanu na stránku ADD (add.latte) obdržím chybu
Undefined variable $form
Jak mám vytvořit komponentu $form ? Mám si zavolat v public function renderAdd($gid) funkci public function createComponentForm($name) ? V ukázce není Presenter pro Components (components/form.latte)
Editoval Joacim (5. 8. 2015 12:34)
- Oli
- Člen | 1215
Jde o tohle
{form $form}
To form
má být bez dolaru. Takovou proměnnou si
nepředáváš a bere se to z toho názvu proměnný
createComponentForm
. Uvnitř formu už ten $form asi nevadí, ale
nevím, takhle jsem to nikdy nevykresloval :-) Kdyžtak se můžeš podívat do
dokumentace jak senormálně vykresluje formulář…
- Joacim
- Člen | 229
Oli napsal(a):
Jde o tohle
{form $form}
To
form
má být bez dolaru. Takovou proměnnou si nepředáváš a bere se to z toho názvu proměnný createComponentForm
. Uvnitř formu už ten $form asi nevadí, ale nevím, takhle jsem to nikdy nevykresloval :-) Kdyžtak se můžeš podívat do dokumentace jak senormálně vykresluje formulář…
Jo už to funguje jak má, díky
- Joacim
- Člen | 229
Jak nastavím, abych měl pouze jeden button „Vybrat soubor“ a poté v okně filesystému jsem si vybral třeba 10 obrázků ? Ted tam mám nagenerováno 22* „Vybrat soubor“ což je hnus, myslel jsem si že ti bude již v Multiupload v composeru nebo musím stáhnout další balík jako je uploadify (User Interfaces u článku MultipleFileUploadv1.1.0)?