--- /dev/null
+<?php
+
+namespace Cubist\Backpack\Http\Controllers;
+
+use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel;
+use Illuminate\Http\UploadedFile;
+
+class CubistFilesorURLUpload
+{
+ public function upload()
+ {
+ $res = [];
+ $className = request()->get('entity');
+ $id = request()->get('entry_id');
+ $attribute = request()->get('attribute');
+ /** @var CubistMagicAbstractModel $instance */
+ $instance = $className::find($id);
+
+ foreach (request()->allFiles() as $files) {
+ if (!is_array($files)) {
+ $files = [$files];
+ }
+ foreach ($files as $file) {
+ /** @var $file UploadedFile */
+ $res[] = $instance->uploadFreeFile($file, $attribute);
+ }
+ }
+ return response()->json($res);
+ }
+}
namespace Cubist\Backpack\Magic\Fields;
+use Cubist\Backpack\CubistBackpackServiceProvider;
+
class FilesOrURL extends Field
{
+ protected $_adminType = 'filesorurl';
+ protected $_viewNamespace = CubistBackpackServiceProvider::NAMESPACE . '::fields';
+ protected $_destination = '';
+
+ public function getDefaultAttributes()
+ {
+ return array_merge(parent::getDefaultAttributes(), ['destination' => $this->_destination]);
+ }
+
+ protected function _postSetAttributes()
+ {
+ parent::_postSetAttributes();
+ $accept = $this->getAttribute('accept', null);
+ if ($accept !== null) {
+ $this->setAttribute('accept', $this->_normalizeAccept($accept));
+ }
+ }
+ protected function _normalizeAccept($accept)
+ {
+ if (is_array($accept)) {
+ $accept = implode(', ', $accept);
+ }
+ $accept = str_replace('*.', '.', $accept);
+ return $accept;
+ }
}
use Cubist\Backpack\Magic\Fields\Composed;
use Cubist\Backpack\Magic\Fields\Datetime;
use Cubist\Backpack\Magic\Fields\Files;
+use Cubist\Backpack\Magic\Fields\FilesOrURL;
use Cubist\Backpack\Magic\Operations\CreateOperation;
use Backpack\CRUD\app\Http\Controllers\Operations\DeleteOperation;
use Cubist\Backpack\Magic\Operations\UpdateOperation;
use Doctrine\DBAL\Schema\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
+use Illuminate\Http\UploadedFile;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
return $saved;
}
+ /**
+ * @param $uploadedFile UploadedFile
+ * @param $attribute string
+ * @return string
+ * @throws \Exception
+ */
+ public function uploadFreeFile($uploadedFile, $attribute)
+ {
+ $field = $this->getField($attribute);
+ if (!$field instanceof FilesOrURL) {
+ throw new \Exception('Field must be FilesOrURL');
+ }
+ $baseDirectory = $this->_getFreeFileBaseDirectory();
+ if (null === $baseDirectory) {
+ throw new \Exception('Base directory must be set');
+ }
+ $dir = \Cubist\Util\Files\Files::mkdir($baseDirectory . '/' . $field->getAttribute('destination', ''));
+ $name = $uploadedFile->getClientOriginalName();
+ $e = explode('.', $name);
+ $ext = array_pop($e);
+ $name = implode('.', $e);
+ $name = Str::slug($name) . '.' . $ext;
+ $uploadedFile->move($dir, $name);
+ return $name;
+ }
+
+ /**
+ * @return string
+ */
+ protected function _getFreeFileBaseDirectory()
+ {
+ return null;
+ }
+
public function saveWithoutFlushingCache($options = [])
{
$this->_flushCacheOnSave = false;
--- /dev/null
+@php
+ $field['wrapper'] = $field['wrapper'] ?? $field['wrapperAttributes'] ?? [];
+ $field['wrapper']['data-init-function'] = $field['wrapper']['data-init-function'] ?? 'bpFieldInitUploadElement';
+ $field['wrapper']['data-field-name'] = $field['wrapper']['data-field-name'] ?? $field['name'];
+
+ $form_id='filesorurl_'.uniqid();
+@endphp
+
+ <!-- text input -->
+@include('crud::fields.inc.wrapper_start')
+<label>{!! $field['label'] !!}</label>
+@include('crud::fields.inc.translatable_icon')
+
+@push('before_scripts')
+ <form id="{{$form_id}}" class="filesorurlupload" action="{{backpack_url('filesorurlupload')}}" method="post"
+ enctype="multipart/form-data">
+ <input type="hidden" name="entity" value="{{ get_class($entry)}}">
+ <input type="hidden" name="entry_id" value="{{ $entry->id}}">
+ <input type="hidden" name="attribute" value="{{$field['name']}}">
+ </form>
+@endpush
+
+{{-- Show the file picker on CREATE form. --}}
+<div class="freefile-file">
+ <input type="file" multiple name="upload[]"
+ @if(isset($field['accept']) && $field['accept'])
+ accept="{{$field['accept']}}"
+ @endif
+ class="freefile-file-input" form="{{$form_id}}">
+ <input type="text" name="{{ $field['name'] }}"
+ value="{{ old(square_brackets_to_dots($field['name'])) ?? $field['value'] ?? $field['default'] ?? '' }}"
+ @include('crud::fields.inc.attributes', ['default_class' => 'form-control freefile-text-input'])
+ >
+ <label class="freefile-file-label" for="customFile"></label>
+</div>
+
+{{-- HINT --}}
+@if (isset($field['hint']))
+ <p class="help-block">{!! $field['hint'] !!}</p>
+@endif
+@include('crud::fields.inc.wrapper_end')
+
+
+{{-- ########################################## --}}
+{{-- Extra CSS and JS for this particular field --}}
+{{-- If a field type is shown multiple times on a form, the CSS and JS will only be loaded once --}}
+@if ($crud->fieldTypeNotLoaded($field))
+ @php
+ $crud->markFieldTypeAsLoaded($field);
+ @endphp
+
+ @push('crud_fields_styles')
+ <style type="text/css">
+
+ .freefile-file {
+ position: relative;
+ display: inline-block;
+ width: 100%;
+ height: calc(1.5em + 0.75rem + 2px);
+ margin-bottom: 0;
+ }
+
+ .freefile-file.loading .freefile-file-input {
+ display: none;
+ }
+
+ .freefile-file.loading .freefile-file-input:lang(en) ~ .freefile-file-label::after {
+ content: "Loading";
+ }
+
+ .freefile-file.loading .freefile-file-input:lang(fr) ~ .freefile-file-label::after {
+ content: "Chargement";
+ }
+
+ .freefile-file-input {
+ position: absolute;
+ z-index: 3;
+ width: 15%;
+ height: calc(1.5em + 0.75rem + 2px);
+ margin: 0;
+ opacity: 0;
+ cursor: pointer;
+ right: 0;
+ }
+
+ .freefile-text-input {
+ position: absolute;
+ z-index: 2;
+ height: calc(1.5em + 0.75rem + 2px);
+ margin: 0;
+ left: 0;
+ width: 85%;
+ border-color: transparent;
+ background-color: transparent;
+ }
+
+ .freefile-text-input:focus {
+ background-color: transparent;
+ border-color: transparent;
+ }
+
+ .freefile-text-input:lang(en) {
+ width: calc(100% - 74px);
+ }
+
+ .freefile-text-input:lang(fr) {
+ width: calc(100% - 87px);
+ }
+
+ .freefile-file-input:lang(en) {
+ width: 74px;
+ }
+
+ .freefile-file-input:lang(fr) {
+ width: 87px;
+ }
+
+ .freefile-text-input:focus ~ .freefile-file-label {
+ border-color: #2f66b3;
+ box-shadow: 0 0 0 0rem rgba(70, 127, 208, 0.25);
+ }
+
+ .freefile-text-input:disabled ~ .freefile-file-label {
+ background-color: #e4e7ea;
+ }
+
+ .freefile-file-input:lang(en) ~ .freefile-file-label::after {
+ content: "Browse";
+ }
+
+ .freefile-file-input:lang(fr) ~ .freefile-file-label::after {
+ content: "Parcourir";
+ }
+
+ .freefile-file-input ~ .freefile-file-label[data-browse]::after {
+ content: attr(data-browse);
+ }
+
+ .freefile-file-label {
+ position: absolute;
+ top: 0;
+ right: 0;
+ left: 0;
+ z-index: 1;
+ height: calc(1.5em + 0.75rem + 2px);
+ padding: 0.375rem 0.75rem;
+ font-weight: 400;
+ line-height: 1.5;
+ color: #5c6873;
+ background-color: #fff;
+ border: 1px solid #e4e7ea;
+ border-radius: 0.25rem;
+ font-weight: 400 !important;
+ }
+
+ .freefile-file-label::after {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 3;
+ display: block;
+ height: calc(1.5em + 0.75rem);
+ padding: 0.375rem 0.75rem;
+ line-height: 1.5;
+ color: #5c6873;
+ content: "Browse";
+ background-color: #f0f3f9;
+ border-left: inherit;
+ border-radius: 0 0.25rem 0.25rem 0;
+ }
+ </style>
+ @endpush
+
+ @push('crud_fields_scripts')
+ <script>
+ jQuery(document).ready(function ($) {
+
+ $(document).on('change', '.freefile-file-input', function () {
+ var parent = $(this).closest('.freefile-file');
+ $(parent).addClass('loading');
+ var form = $("#" + $(this).attr('form'));
+ var f = $(form).ajaxSubmit({dataType: 'json'});
+ var xhr = f.data('jqxhr');
+ xhr.done(function (data) {
+ $(parent).find('.freefile-text-input').val(data[0]);
+ $(parent).removeClass('loading');
+ });
+ });
+ });
+ </script>
+ @endpush
+@endif