У меня есть объект данных под названием «Project», который имеет отношение $ has_many к другому объекту данных под названием «ProjectExpenseForm». В интерфейсе сайта находится форма SilverStripe, которая используется для обновления некоторых полей проекта. Новые файлы и изображения также можно загружать через интерфейсную форму.
Я использую модуль SilverStripe Dropzone Master (https://github.com/unclecheese/silverstripe-dropzone) для создания поля загрузки в форме внешнего интерфейса. Мне удалось заставить его работать, чтобы он сохранял все загрузки в правильную папку в каталоге ресурсов (у каждого проекта есть папка для загруженных файлов, а настройка - assets / projects / [идентификатор проекта] / files /). Однако я не уверен, как прикрепить / связать эти загруженные файлы с проектом. Хорошо, что они загружаются в нужную папку, но если файлы не связаны с проектом, это нехорошо.
Вот код интерфейсной формы:
public function UpdateMyProjectProfileForm()
{
$fieldsArr = array();
$member = Member::currentUser();
if (!$member) {
return "<div class='text-danger'>Error: must be logged in to view this page.</div>";
}
$request = $this->getRequest();
$projectName = $request->param('ProjectName');
$projectNameID = explode("-", $projectName);
$projectNameID = $projectNameID[0];
if ($member->inGroup('project-lead')) {
$project = Project::get()
->filter(
array(
"ProjectLeadID" => $member->ID,
"ID" => $projectNameID
)
)
->first();
$name = ReadonlyField::create('Name', 'Name of Project', $project->Name);
$firstName = ReadonlyField::create('FirstName', 'First Name of Project Manager', $project->FirstName);
$lastName = ReadonlyField::create('LastName', 'Last Name of Project Manager', $project->LastName);
$phone = ReadonlyField::create('Phone', "Phone Number", $project->Phone);
$emailAddress = ReadonlyField::create('Email', "Manager Email", $project->Email);
$notes = TextareaField::create('Notes', 'Notes', $project->Notes);
$projectSummary = TextareaField::create('ProjectSummary', "Project Summary", $project->ProjectSummary);
$imageUploader = FileAttachmentField::create('MyFile', 'Upload a file')
->setView('grid')
->setMultiple(true)
->setFolderName("projects/".$project->ID.'/expenses'); //THIS WORKS - Stores the file(s) uploaded to the proper directory
array_push($fieldsArr, $name);
array_push($fieldsArr, $firstName);
array_push($fieldsArr, $lastName);
array_push($fieldsArr, $phone);
array_push($fieldsArr, $emailAddress);
array_push($fieldsArr, $notes);
array_push($fieldsArr, $projectSummary);
array_push($fieldsArr, $imageUploader);
$fields = new FieldList($fieldsArr);
$updateButton = FormAction::create('update', 'Update')
->addExtraClass("btn btn-default commonBtn");
$actions = new FieldList($updateButton);
$required = new RequiredFields(
array('Name', 'Notes', 'ProjectSummary')
);
$form = new Form($this, $projectName . '/UpdateMyProjectProfileForm', $fields, $actions, $required);
$form->setFormMethod('POST', true);
return $form;
}
}
public function update($data, Form $form)
{
$member = Member::currentUser();
$request = $this->getRequest();
$projectName = $request->param('ProjectName');
$projectNameID = explode("-", $projectName);
$projectNameID = $projectNameID[0];
$project = Project::get()
->filter(
array(
"ProjectLeadID" => $member->ID,
"ID" => $projectNameID
)
)
->first();
if ($data['Name'] == "") {
$form->addErrorMessage("Name", "Project Name is required.", "text-danger");
return $this->redirectBack();
}
if ($data['Notes'] == "") {
$form->addErrorMessage("Notes", "Notes is required.", "text-danger");
return $this->redirectBack();
}
if ($data['ProjectSummary'] == "") {
$form->addErrorMessage("ProjectSummary", "Project Summary is required.", "text-danger");
return $this->redirectBack();
}
$member = Member::currentUser();
if (!$member) {
$form->addErrorMessage("FirstName", "Error: user profile not found.", "text-danger");
return $this->redirectBack();
}
$project->Name = $data['Name'];
$project->Notes = $data['Notes'];
$project->ProjectSummary = $data['ProjectSummary'];
$project->write();
$form->sessionMessage("Project profile successfully updated.", 'text-success');
return $this->redirectBack();
}
Вот класс проекта:
public function UpdateMyProjectProfileForm()
{
$fieldsArr = array();
$member = Member::currentUser();
if (!$member) {
return "<div class='text-danger'>Error: must be logged in to view this page.</div>";
}
$request = $this->getRequest();
$projectName = $request->param('ProjectName');
$projectNameID = explode("-", $projectName);
$projectNameID = $projectNameID[0];
if ($member->inGroup('project-lead')) {
$project = Project::get()
->filter(
array(
"ProjectLeadID" => $member->ID,
"ID" => $projectNameID
)
)
->first();
$name = ReadonlyField::create('Name', 'Name of Project', $project->Name);
$firstName = ReadonlyField::create('FirstName', 'First Name of Project Manager', $project->FirstName);
$lastName = ReadonlyField::create('LastName', 'Last Name of Project Manager', $project->LastName);
$phone = ReadonlyField::create('Phone', "Phone Number", $project->Phone);
$emailAddress = ReadonlyField::create('Email', "Manager Email", $project->Email);
$notes = TextareaField::create('Notes', 'Notes', $project->Notes);
$projectSummary = TextareaField::create('ProjectSummary', "Project Summary", $project->ProjectSummary);
$imageUploader = FileAttachmentField::create('MyFile', 'Upload a file')
->setView('grid')
->setMultiple(true)
->setFolderName("projects/".$project->ID.'/expenses');
array_push($fieldsArr, $name);
array_push($fieldsArr, $firstName);
array_push($fieldsArr, $lastName);
array_push($fieldsArr, $phone);
array_push($fieldsArr, $emailAddress);
array_push($fieldsArr, $notes);
array_push($fieldsArr, $projectSummary);
array_push($fieldsArr, $imageUploader);
$fields = new FieldList($fieldsArr);
$updateButton = FormAction::create('update', 'Update')
->addExtraClass("btn btn-default commonBtn");
$actions = new FieldList($updateButton);
$required = new RequiredFields(
array('Name', 'Notes', 'ProjectSummary')
);
$form = new Form($this, $projectName . '/UpdateMyProjectProfileForm', $fields, $actions, $required);
$form->setFormMethod('POST', true);
return $form;
}
}
public function update($data, Form $form)
{
$member = Member::currentUser();
$request = $this->getRequest();
$projectName = $request->param('ProjectName');
$projectNameID = explode("-", $projectName);
$projectNameID = $projectNameID[0];
$project = Project::get()
->filter(
array(
"ProjectLeadID" => $member->ID,
"ID" => $projectNameID
)
)
->first();
if ($data['Name'] == "") {
$form->addErrorMessage("Name", "Project Name is required.", "text-danger");
return $this->redirectBack();
}
if ($data['Notes'] == "") {
$form->addErrorMessage("Notes", "Notes is required.", "text-danger");
return $this->redirectBack();
}
if ($data['ProjectSummary'] == "") {
$form->addErrorMessage("ProjectSummary", "Project Summary is required.", "text-danger");
return $this->redirectBack();
}
$member = Member::currentUser();
if (!$member) {
$form->addErrorMessage("FirstName", "Error: user profile not found.", "text-danger");
return $this->redirectBack();
}
$project->Name = $data['Name'];
$project->Notes = $data['Notes'];
$project->ProjectSummary = $data['ProjectSummary'];
$project->write();
$form->sessionMessage("Project profile successfully updated.", 'text-success');
return $this->redirectBack();
}
Класс проекта (многое было удалено - я просто сохранил соответствующие части):
<?php
class Project extends DataObject
{
private static $db = array(
'Name' => 'varchar(255)',,
'FirstName' => 'varchar(255)',
'LastName' => 'varchar(255)',
'ProjectSlug' => 'varchar(255)',
'Email' => 'varchar(255)',
'Phone' => 'varchar(255)',
'Notes' => 'Text',
'ProjectSummary' => 'Text',
);
// One-to-one relationship with gallery page
private static $has_one = array(
'MainImage' => 'Image',
"Status" => 'ProjectStatus',
'ProjectLead' => 'ProjectLead'
);
private static $has_many = array(
'AdditionalProjectImages' => 'AdditionalProjectImage',
'ProjectExpenseForms' => 'ProjectExpenseForm',
);
// Tell the datagrid what fields to show in the table
private static $summary_fields = array(
'ID' => 'ID',
'Name' => 'Project',
);
// tidy up the CMS by not showing these fields
public function getCMSFields()
{
$fields = parent::getCMSFields();
$fields->removeByName("ProjectExpenseForms");
$fields->removeByName("AdditionalProjectImages");
$fields->addFieldToTab("Root.Main", new TextField("ProjectSlug", "Project Slug"));
$projectMainImgUploadField = new UploadField("MainImage", "Project Main Image");
$projectMainImgUploadField->setFolderName("projects/".$this->ID.'/images');
$fields->addFieldToTab('Root.Main', $projectMainImgUploadField);
$fields->addFieldToTab("Root.Main", new TextField("Name", "Project Name"));
$fields->addFieldToTab("Root.Main", new TextField("FirstName", "First Name"));
$fields->addFieldToTab("Root.Main", new TextField("LastName", "Last Name"));
$fields->addFieldToTab("Root.Main", new TextField("Phone", "Phone Number"));
$fields->addFieldToTab("Root.Main", new TextField("Email", "Email Address"));
$fields->addFieldToTab("Root.Main", new TextareaField("Notes", "Notes"));
$fields->addFieldToTab("Root.Main", new TextareaField("ProjectSummary", "Project Summary"));
//EXPENSE FORMS
$expensesGridFieldConfig = GridFieldConfig_RecordEditor::create();
$expensesGridFieldConfig->addComponent(new GridFieldBulkUpload());
$expensesGridFieldConfig->addComponent(new GridFieldSortableRows('SortOrder'));
$expensesGridFieldConfig->getComponentByType('GridFieldBulkUpload')
->setUfSetup('setFolderName',"projects/" . $this->ID . "/expenses")
->setUfConfig('sequentialUploads', true);
$expensesGridFieldConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(array(
// field from drawer class => label in UI
'ID' => 'ID',
'Title'=> 'Title'
));
$expensesGridField = new GridField(
"ProjectExpenseForms",
"Project Expense Forms",
$this->ProjectExpenseForms()->sort("SortOrder"),
$expensesGridFieldConfig
);
$fields->addFieldToTab('Root.Project Expense Forms', $expensesGridField);
public function getExpenses(){
return $this->ProjectExpenseForms();
}
public function onBeforeWrite()
{
parent::onBeforeWrite();
if ($this->StatusID == "" || $this->StatusID == 0 || is_null($this->StatusID)) {
$siteConfig = SiteConfig::current_site_config();
$this->StatusID = $siteConfig->DefaultProjectStatusID;
}
//email the assigned grantor
if ($this->isChanged('ProjectGrantorID', DataObject::CHANGE_VALUE) && $this->ProjectGrantorID != 0) {
$this->sendGrantorEmail();
}
}
public function onAfterWrite()
{
parent::onAfterWrite();
//If the project does not have the appropriate folders already created, it's time to create them.
Folder::find_or_make("/projects/" . $this->ID . "/expenses");
Folder::find_or_make("/projects/" . $this->ID . "/images");
}
}
class ProjectAdmin extends ModelAdmin
{
private static $managed_models = array('Project');
private static $url_segment = 'Projects';
private static $menu_title = 'Projects';
}
и класс ProjectExpenseForm (многое было удалено - я просто включил соответствующие части):
<?php
class ProjectExpenseForm extends DataObject {
private static $db = array(
'SortOrder' => 'Int',
);
// One-to-one relationship with gallery page
private static $has_one = array(
'ProjectExpenseFile' => 'File',
'Project' => 'Project'
);
// tidy up the CMS by not showing these fields
public function getCMSFields() {
$fields = parent::getCMSFields();
$projectExpenseUploadField = new UploadField("ProjectExpenseFile", "Project Expense File");
$projectExpenseUploadField->setFolderName("projects/".$this->ProjectID.'/expenses');
$fields->addFieldToTab('Root.Main', $projectExpenseUploadField);
$fields->removeFieldFromTab("Root.Main","SortOrder");
return $fields;
}
}






Поскольку вы знаете, в какой папке сохраняются файлы на assets/projects/[project id]/files/, и файлы уникальны для этого проекта, вы можете просмотреть файлы в цикле и использовать DB::query, чтобы связать их с проектом.
В методе update файла UpdateMyProjectProfileForm я бы сделал что-то вроде.
$folderPath = 'assets/projects/' . $projectNameID . '/files/';
$folder = DataList::create('Folder')->filter('Filename', $folderPath)->first();
if ($folder) {
$images = DataList::create('Image')->filter('ParentID', $folder->ID);
foreach ($images as $image) {
DB::query('INSERT INTO Project_AdditionalProjectImages (ProjectID, AdditionalProjectImagesID) VALUES (' . $projectNameID . ',' . $image->ID . ')');
}
}
Вы также можете добавить ProjectLeadID в запрос, чтобы сделать его более безопасным. Вам нужно будет проверить имя вашей таблицы, так как Project_AdditionalProjectImages может быть неправильным.
Вам нужно передать отношение к File AttachmentField вместо MyFile
$imageUploader = FileAttachmentField::create('MyFile', 'Upload a file')
В вашем случае это AdditionalProjectImages, потому что вы так назвали его в своем has_many.
private static $has_many = array(
'AdditionalProjectImages' => 'Image'
)
Они должны указывать на класс изображения вместо AdditionalProjectImage.
Итак, ваш FileAttachmentField должен выглядеть так:
$imageUploader = FileAttachmentField::create('AdditionalProjectImages', 'Upload a file')
И поскольку каждому $ has_many нужен $ has_one, вам нужен has один в классе изображения. Итак, вам нужно расширение:
ImageExtension extends Image
{
public static $has_one = [
'ProjectImages' => 'Project'
];
}
Запустите dev / build / flush, Silverstripe прикрепит / свяжет эти загруженные файлы с вашим проектом, если вы сделаете это, как указано выше.
На всякий случай, если вы не знаете, что есть новый форум для silverstripe: SilverStripe Форум, а также есть слабый канал для пользователей silverstripe.
Я бы попробовал 'AdditionalProjectImages' => 'ImageExtension' вместо 'AdditionalProjectImages' => 'Image'.
@GavinBruce Я попробовал, и он устранил ошибку, но при загрузке файлов они по-прежнему не связаны с проектом: \
Мое плохое "нет" () для расширения
У Das Image есть ProjectImagesID? И собственно его dev / build /? Flush.
Вы брали эти уроки https://www.silverstripe.org/learn/lessons/v3. Мне потребовалось время, чтобы понять орму, но как только вы ее получите, вы никогда не захотите работать без нее.
Я пробовал это, но получаю сообщение об ошибке: «Неперехваченное исключение: не найдено has_one в классе« Image », для отношения has_many от« Project »к« Image »требуется has_one в« Image »». Я создал класс расширения для Image так же, как вы предложили. Хотя, не уверен, почему после изображения для расширения стоит ()?