tethys/app/Http/Controllers/Publish/EditorController.php
Arno Kaimbacher 7d1406ee5c - array/string Helpers: Laravel Convert old array and string helpers into their modern class-based methods.
-  Use Laravel Carbon: Laravel provides an Illuminate\Support\Carbon class which wraps the underlying Carbon class. By using this class, you gain access to some additional testing methods and create separation between your code and underlying dependencies.
2022-08-12 07:53:27 +00:00

793 lines
30 KiB
PHP

<?php
namespace App\Http\Controllers\Publish;
use App\Exceptions\GeneralException;
use App\Http\Controllers\Controller;
use App\Http\Requests\DocumentRequest;
use App\Models\Dataset;
use App\Models\DatasetReference;
use App\Models\Description;
use App\Models\File;
use App\Models\License;
use App\Models\Person;
use App\Models\Project;
use App\Models\Subject;
use App\Models\Title;
use App\Models\User;
use App\Rules\RdrFilesize;
use App\Rules\RdrFiletypes;
// use Illuminate\View\View;
use Illuminate\Support\Carbon;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\View;
use \Exception;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Log;
use App\Models\DatasetIdentifier;
use App\Models\Oai\OaiModelError;
use App\Exceptions\OaiModelException;
use App\Interfaces\DoiInterface;
use App\Library\Search\SolariumAdapter;
class EditorController extends Controller
{
/**
* Holds xml representation of document information to be processed.
*
* @var \DomDocument Defaults to null.
*/
protected $xml = null;
/**
* Holds the stylesheet for the transformation.
*
* @var \DomDocument Defaults to null.
*/
protected $xslt = null;
/**
* Holds the xslt processor.
*
* @var \XSLTProcessor Defaults to null.
*/
protected $proc = null;
public function __construct(DoiInterface $DoiClient)
{
$this->doiClient = $DoiClient;
//$this->middleware('auth');
$this->xml = new \DomDocument('1.0', 'UTF-8');
$this->proc = new \XSLTProcessor();
}
/**
* Display a listing of released and accepted datasets.
*
* @return \Illuminate\Http\Response
*/
public function index(): \Illuminate\Contracts\View\View
{
$user = Auth::user();
$user_id = $user->id;
$builder = Dataset::query();
//"select * from [documents] where [server_state] in (?) or ([server_state] = ? and [editor_id] = ?)"
$datasets = $builder
->where('server_state', 'released')
// ->whereIn('server_state', ['released'])
->orWhere(function ($query) use ($user_id) {
$query->whereIn('server_state', ['editor_accepted', 'rejected_reviewer', 'reviewed', 'published'])
->where('editor_id', $user_id)->doesntHave('identifier', 'and');
})
->orderByDesc('server_date_modified')
->get();
// return View::make('workflow.editor.index', compact('datasets'));
return View::make('workflow.editor.index', [
'datasets' => $datasets,
]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function receive($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::with('user:id,login')->findOrFail($id);
return View::make('workflow.editor.receive', [
'dataset' => $dataset,
]);
}
public function receiveUpdate(Request $request, $id)
{
$dataset = Dataset::findOrFail($id);
try {
$dataset->setServerState("editor_accepted");
$user = Auth::user();
$dataset->editor()->associate($user)->save();
$dataset->save();
// return redirect()->back();
return redirect()->route('publish.workflow.editor.index');
} catch (Exception $e) {
throw new GeneralException(trans('exceptions.publish.accept.update_error'));
}
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::findOrFail($id);
$dataset->load('licenses', 'authors', 'contributors', 'titles', 'abstracts', 'files', 'coverage', 'subjects', 'references');
$titleTypes = ['Main' => 'Main', 'Sub' => 'Sub', 'Alternative' => 'Alternative', 'Translated' => 'Translated', 'Other' => 'Other'];
$descriptionTypes = [
'Abstract' => 'Abstract', 'Methods' => 'Methods', 'Series_information' => 'Series_information',
'Technical_info' => 'Technical_info', 'Translated' => 'Translated', 'Other' => 'Other'
];
$languages = DB::table('languages')
->where('active', true)
->pluck('part1', 'part1');
$messages = DB::table('messages')
->pluck('help_text', 'metadata_element');
$projects = Project::pluck('label', 'id');
$datum = date('Y-m-d');
$nowYear = substr($datum, 0, 4);
$years = array();
for ($jahr = 1990; $jahr <= $nowYear; $jahr++) {
$years[$jahr] = $jahr;
}
$languages = DB::table('languages')
->where('active', true)
->pluck('part1', 'part1');
$contributorTypes = Config::get('enums.contributor_types');
$nameTypes = Config::get('enums.name_types');
// $options = License::all('id', 'name_long');
$licenses = License::select('id', 'name_long', 'link_licence')
->orderBy('sort_order')
->get();
// $checkeds = $dataset->licenses->pluck('id')->toArray();
$checkeds = $dataset->licenses->first()->id;
$keywordTypes = ['uncontrolled' => 'uncontrolled', 'swd' => 'swd'];
$referenceTypes = ["DOI", "Handle", "ISBN", "ISSN", "URL", "URN"];
$referenceTypes = array_combine($referenceTypes, $referenceTypes);
$relationTypes = [
"IsSupplementTo", "IsSupplementedBy", "IsContinuedBy", "Continues",
"IsNewVersionOf", "IsPartOf", "HasPart", "Compiles", "IsVariantFormOf"
];
$relationTypes = array_combine($relationTypes, $relationTypes);
return View::make(
'workflow.editor.edit',
compact(
'dataset',
'titleTypes',
'descriptionTypes',
'contributorTypes',
'nameTypes',
'languages',
'messages',
'projects',
'licenses',
'checkeds',
'years',
'languages',
'keywordTypes',
'referenceTypes',
'relationTypes'
)
);
}
//https://stackoverflow.com/questions/17480200/using-laravel-how-do-i-create-a-view-that-will-update-a-one-to-many-relationshi?rq=1
// https://laravel.io/forum/06-11-2014-how-to-save-eloquent-model-with-relations-in-one-go
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(DocumentRequest $request, $id): RedirectResponse
{
$rules = [
'type' => 'required|min:3',
'titles.*.value' => 'required|min:4|max:255',
'titles.*.language' => 'required',
'descriptions.*.value' => 'required|min:4|max:2500',
'descriptions.*.language' => 'required',
'coverage.x_min' => [
'required',
'regex:/^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/',
],
'coverage.y_min' => [
'required',
'regex:/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/',
],
'coverage.x_max' => [
'required',
'regex:/^[-]?((((1[0-7][0-9])|([0-9]?[0-9]))\.(\d+))|180(\.0+)?)$/',
],
'coverage.y_max' => [
'required',
'regex:/^[-]?(([0-8]?[0-9])\.(\d+))|(90(\.0+)?)$/',
],
'subjects' => 'required|array|min:3',
'subjects.*.value' => 'required|string',
'subjects.*.type' => 'required|string',
'files' => 'required|array|min:1',
'files.*.label' => 'required|string',
];
$customMessages = [
'subjects.min' => 'Minimal three keywords are required.',
'subjects.*.type.required' => 'The types of all keywords are required.',
'files.min' => 'Minimal one file is required.',
];
if (null != $request->file('files')) {
$data = $request->all();
$files = count($request->input('files')) - 1;
foreach (range(0, $files) as $index) {
// $rules['files.' . $index] = 'image|max:2048';
$rules['files.' . $index . '.file'] = [new RdrFilesize($index + 1), 'file', new RdrFiletypes()];
}
}
$validator = Validator::make($request->all(), $rules, $customMessages);
if (!$validator->fails()) {
$dataset = Dataset::findOrFail($id);
$data = $request->all();
$input = $request->except(
'abstracts',
'licenses',
'authors',
'contributors',
'titles',
'coverage',
'subjects',
'references',
'files'
);
$licenses = $request->input('licenses');
//$licenses = $input['licenses'];
$dataset->licenses()->sync($licenses);
$dataset->authors()->sync([]);
//store authors
if (isset($data['authors'])) {
// $data_to_sync = [];
$index = 0;
foreach ($request->get('authors') as $key => $person) {
$pivot_data = ['role' => 'author', 'sort_order' => $index + 1, 'allow_email_contact' => false];
// if ($galery_id == $request->get('mainPicture')) $pivot_data = ['main' => 1];
if (isset($person['id'])) {
// $data_to_sync[$person['id']] = $pivot_data;
$dataset->persons()->attach($person['id'], $pivot_data);
} else {
$dataPerson = new Person($person);
$dataPerson->status = true;
// $dataPerson->name_type = "Organizational";
$dataset->persons()->save($dataPerson, $pivot_data);
}
$index++;
}
// $dataset->persons()->sync($data_to_sync);
}
$dataset->contributors()->sync([]);
//store contributors
if (isset($data['contributors'])) {
// $data_to_sync = [];
$index = 0;
foreach ($request->get('contributors') as $key => $person) {
$pivot_data = ['role' => 'contributor', 'sort_order' => $index + 1, 'allow_email_contact' => false];
$pivot_data = array_merge($pivot_data, $person['pivot']);
// if ($galery_id == $request->get('mainPicture')) $pivot_data = ['main' => 1];
if (isset($person['id'])) {
// $data_to_sync[$person['id']] = $pivot_data;
$dataset->persons()->attach($person['id'], $pivot_data);
} else {
$dataPerson = new Person($person);
$dataPerson->status = true;
// $dataPerson->name_type = "Organizational";
$dataset->persons()->save($dataPerson, $pivot_data);
}
$index++;
}
// $dataset->persons()->sync($data_to_sync);
}
//save the titles:
$titles = $request->input('titles');
if (is_array($titles) && count($titles) > 0) {
foreach ($titles as $key => $formTitle) {
// if (isset($key) && $key != 'undefined') {
if (isset($formTitle['id'])) {
$title = Title::findOrFail($formTitle['id']);
$title->value = $formTitle['value'];
$title->language = $formTitle['language'];
$title->type = $formTitle['type'];
if ($title->isDirty()) {
$title->save();
}
} else {
$title = new Title($formTitle);
$dataset->titles()->save($title);
}
}
}
//save the abstracts:
$abstracts = $request->input('abstracts');
if (is_array($abstracts) && count($abstracts) > 0) {
foreach ($abstracts as $key => $formAbstract) {
// if (isset($key) && $key != 'undefined') {
if (isset($formAbstract['id'])) {
$abstract = Description::findOrFail($formAbstract['id']);
$abstract->value = $formAbstract['value'];
$abstract->language = $formAbstract['language'];
if ($abstract->isDirty()) {
$abstract->save();
}
} else {
$abstract = new Description($formAbstract);
$dataset->abstracts()->save($abstract);
}
}
}
//save the references:
$references = $request->input('references');
if (is_array($references) && count($references) > 0) {
foreach ($references as $key => $formReference) {
// if (isset($key) && $key != 'undefined') {
if (isset($formReference['id'])) {
$reference = DatasetReference::findOrFail($formReference['id']);
$reference->value = $formReference['value'];
$reference->label = $formReference['label'];
$reference->type = $formReference['type'];
$reference->relation = $formReference['relation'];
if ($reference->isDirty()) {
$reference->save();
}
} else {
$reference = new DatasetReference($formReference);
$dataset->references()->save($reference);
}
}
}
//save the keywords:
$keywords = $request->input('subjects');
if (is_array($keywords) && count($keywords) > 0) {
foreach ($keywords as $key => $formKeyword) {
if (isset($formKeyword['id'])) {
// is readonly
$subject = Subject::findOrFail($formKeyword['id']);
// $subject->value = $formKeyword['value'];
// $subject->type = $formKeyword['type'];
// if ($subject->isDirty()) {
// $subject->save();
// }
} else {
// $subject = new Subject($formKeyword);
// $dataset->subjects()->save($subject);
$keyword = Subject::firstOrCreate(
['value' => $formKeyword['value'], 'language' => $formKeyword['language']],
$formKeyword
);
$dataset->subjects()->attach($keyword);
}
}
}
//save the files:
$files = $request->get('files');
// $files = $request->file('files');
if (is_array($files) && count($files) > 0) {
$index = 1;
foreach ($files as $key => $formFile) {
// if (isset($key) && $key != 'undefined') {
if (isset($formFile['id'])) {
$file = File::findOrFail($formFile['id']);
$file->label = $formFile['label'];
if ($file->isDirty()) {
$file->save();
}
} else {
$uploads = $request->file('uploads');
$fileIndex = $formFile['file'];
$file = $uploads[$fileIndex];
// $file = new \Illuminate\Http\UploadedFile($file);
$label = urldecode($formFile['label']);
$sort_order = $index; //$formFile['sort_order'];
$fileName = "file-" . time() . '.' . $file->getClientOriginalExtension();
$mimeType = $file->getMimeType();
$datasetFolder = 'files/' . $dataset->id;
$path = $file->storeAs($datasetFolder, $fileName);
$size = Storage::size($path);
//$path = Storage::putFile('files', $image, $fileName);
$fileDb = new File([
'path_name' => $path,
'file_size' => $size,
'mime_type' => $mimeType,
'label' => $label,
'sort_order' => $sort_order,
'visible_in_frontdoor' => 1,
'visible_in_oai' => 1,
]);
//$test = $file->path_name;
$dataset->files()->save($fileDb);
$fileDb->createHashValues();
}
$index++;
}
}
// save coverage
if (isset($data['coverage']) && !$this->containsOnlyNull($data['coverage'])) {
$formCoverage = $request->input('coverage');
$coverage = $dataset->coverage()->updateOrCreate(
['dataset_id' => $dataset->id],
$formCoverage
);
} elseif (isset($data['coverage']) && $this->containsOnlyNull($data['coverage'])
&& !is_null($dataset->coverage)
) {
$dataset->coverage()->delete();
}
$dataset->fill($input);
// $dataset->creating_corporation = "Peter";
if (!$dataset->isDirty()) {
$time = new \Illuminate\Support\Carbon();
$dataset->setUpdatedAt($time);
}
// $dataset->save();
if ($dataset->update($input)) {
//event(new DatasetUpdated($dataset));
session()->flash('flash_message', 'You have updated 1 dataset!');
return redirect()->route('publish.workflow.editor.index');
}
} else {
//TODO Handle validation error
//pass validator errors as errors object for ajax response
// return response()->json([
// 'success' => false,
// 'errors' => $validator->errors()->all(),
// ], 422);
// $errors = $validator->errors();
return back()->withErrors($validator);
// return redirect()->route('publish.workflow.submit.edit', ['id' => $id])->withInput()
// ->withErrors($validator);
}
throw new GeneralException(trans('exceptions.backend.dataset.update_error'));
}
private function containsOnlyNull($input)
{
return empty(array_filter($input, function ($a) {
return $a !== null;
}));
}
public function download($id)
{
//$report = $this->report->find($id);
$file = File::findOrFail($id);
$file_path = public_path('storage/' . $file->path_name);
$ext = \Illuminate\Support\Facades\File::extension($file_path);
return response()->download($file_path, $file->label . "." . $ext, ['Content-Type:' . $file->mime_type]);
// return response()->download($file_path, $file->label, ['Content-Type:' . $file->mime_type]);
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function approve($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::with('user:id,login')->findOrFail($id);
$reviewers = User::whereHas('roles', function ($q) {
$q->where('name', 'reviewer');
})->pluck('login', 'id');
return View::make('workflow.editor.approve', [
'dataset' => $dataset,
'reviewers' => $reviewers,
]);
}
public function approveUpdate(Request $request, $id)
{
// $dataset = Dataset::findOrFail($id);
// try {
// $dataset->setServerState("approved");
// $user = Auth::user();
// $dataset->reviewer()->associate($user)->save();
// $dataset->save();
// // return redirect()->back();
// return redirect()->route('publish.workflow.editor.index');
// } catch (Exception $e) {
// throw new GeneralException(trans('exceptions.publish.approve.update_error'));
// }
$dataset = Dataset::findOrFail($id);
$input = $request->all();
$input['server_state'] = 'approved';
if ($dataset->reject_reviewer_note != null) {
$input['reject_reviewer_note'] = null;
}
if ($dataset->update($input)) {
// event(new PageUpdated($page));
return redirect()
->route('publish.workflow.editor.index')
->with('flash_message', 'You have approved one dataset!');
}
throw new GeneralException(trans('exceptions.publish.approve.update_error'));
}
/**
* Reject dataset back to editor
*
* @param int $id
* @return \Illuminate\View\View
*/
public function reject($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::with('user:id,login')->findOrFail($id);
return View::make('workflow.editor.reject', [
'dataset' => $dataset,
]);
}
public function rejectUpdate(Request $request, $id)
{
$this->validate($request, [
'reject_editor_note' => 'required|min:10|max:500',
'server_state' => 'required',
]);
$dataset = Dataset::findOrFail($id);
$input = $request->all();
//$input['server_state'] = 'rejected_editor';
if ($dataset->update($input)) {
// event(new PageUpdated($page));
return redirect()
->route('publish.workflow.editor.index')
->with('flash_message', 'You have successfully rejected one dataset! The submitter will be informed.');
}
throw new GeneralException(trans('exceptions.publish.review.update_error'));
}
/**
* Display the specified dataset for publishing.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function publish($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::query()
->with([
'titles',
'persons' => function ($query) {
$query->wherePivot('role', 'author');
},
])->findOrFail($id);
return View::make('workflow.editor.publish', [
'dataset' => $dataset,
]);
}
public function publishUpdate(Request $request, $id)
{
$dataset = Dataset::findOrFail($id);
$max = Dataset::max('publish_id');
$publish_id = 0;
if ($max != null) {
$publish_id = $max + 1;
} else {
$publish_id = $publish_id + 1;
}
$input = $request->all();
$input['server_state'] = 'published';
$input['server_date_published'] = Carbon::now()->toDateTimeString(); // Produces something like "2019-03-11 12:25:00"
$input['publish_id'] = $publish_id;
if ($dataset->update($input)) {
// event(new PageUpdated($page));
return redirect()
->route('publish.workflow.editor.index')
->with('flash_message', 'You have successfully published the dataset!');
}
throw new GeneralException(trans('exceptions.publish.publish.update_error'));
}
/**
* Display the specified dataset for publishing.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function doiCreate($id): \Illuminate\Contracts\View\View
{
$dataset = Dataset::query()
->with([
'titles',
'persons' => function ($query) {
$query->wherePivot('role', 'author');
},
])->findOrFail($id);
return View::make('workflow.editor.doi', [
'dataset' => $dataset,
]);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function doiStore(Request $request, $publish_id)
{
$dataId = $publish_id; //$request->input('publish_id');
// Setup stylesheet
$this->loadStyleSheet(public_path() . '/prefixes/doi_datacite.xslt');
// set timestamp
$date = new \DateTime();
$unixTimestamp = $date->getTimestamp();
$this->proc->setParameter('', 'unixTimestamp', $unixTimestamp);
$prefix = "";
$base_domain = "";
$datacite_environment = config('tethys.datacite_environment');
if ($datacite_environment == "debug") {
$prefix = config('tethys.datacite_test_prefix');
$base_domain = config('tethys.test_base_domain');
} elseif ($datacite_environment == "production") {
$prefix = config('tethys.datacite_prefix');
$base_domain = config('tethys.base_domain');
}
// $prefix = config('tethys.datacite_prefix');
$this->proc->setParameter('', 'prefix', $prefix);
$repIdentifier = "tethys";
$this->proc->setParameter('', 'repIdentifier', $repIdentifier);
$this->xml->appendChild($this->xml->createElement('Datasets'));
$dataset = Dataset::where('publish_id', '=', $dataId)->firstOrFail();
if (is_null($dataset)) {
throw new OaiModelException('Dataset is not available for registering DOI!', OaiModelError::NORECORDSMATCH);
}
$dataset->fetchValues();
$xmlModel = new \App\Library\Xml\XmlModel();
$xmlModel->setModel($dataset);
$xmlModel->excludeEmptyFields();
$cache = ($dataset->xmlCache) ? $dataset->xmlCache : new \App\Models\XmlCache();
$xmlModel->setXmlCache($cache);
$domNode = $xmlModel->getDomDocument()->getElementsByTagName('Rdr_Dataset')->item(0);
$this->addAlternateLandingPageAttribute($domNode, $dataset->publish_id);
$node = $this->xml->importNode($domNode, true);
$this->addSpecInformation($node, 'data-type:' . $dataset->type);
$this->xml->documentElement->appendChild($node);
$xmlMeta = $this->proc->transformToXML($this->xml);
// Log::alert($xmlMeta);
//create doiValue and correspunfing landingpage of tehtys
$doiValue = $prefix . '/tethys.' . $dataset->publish_id;
// $appUrl = config('app.url');
// $landingPageUrl = $base_domain . "/dataset/" . $dataset->publish_id;
$landingPageUrl = 'https://doi.' . get_domain($base_domain) . "/" . $prefix . "/tethys." . $dataset->publish_id;
$response = $this->doiClient->registerDoi($doiValue, $xmlMeta, $landingPageUrl);
// if operation successful, store dataste identifier
if ($response->getStatusCode() == 201) {
$doi = new DatasetIdentifier();
$doi['value'] = $doiValue; //$landingPageUrl;
$doi['dataset_id'] = $dataset->id;
$doi['type'] = "doi";
$doi['status'] = "findable";
if ($doi->save()) {
// touch unnecessary, save() also updates datasat modified date
// $doi->touch();
$dataset = Dataset::where('publish_id', '=', $dataId)->firstOrFail();
// add to solr
try {
$service = new SolariumAdapter("solr", config('solarium'));
$service->addDatasetsToIndex($dataset);
} catch (Exception $e) {
$this->error(__METHOD__ . ': ' . 'Indexing document ' . $dataset->id . ' failed: ' . $e->getMessage());
}
return redirect()
->route('publish.workflow.editor.index')
->with('flash_message', 'You have successfully created a DOI for the dataset!');
}
} else {
$message = 'unexpected DataCite MDS response code ' . $response->getStatusCode();
// $this->log($message, 'err');
throw new GeneralException($message);
}
}
/**
* Add the landingpage attribute to Rdr_Dataset XML output.
*
* @param \DOMNode $document Rdr_Dataset XML serialisation
* @param string $docid Id of the dataset
* @return void
*/
private function addAlternateLandingPageAttribute(\DOMNode $document, $dataid)
{
$base_domain = config('tethys.base_domain');
$url ='https://' . get_domain($base_domain) . "/dataset/" . $dataid;
$owner = $document->ownerDocument;
$attr = $owner->createAttribute('landingpage');
$attr->appendChild($owner->createTextNode($url));
$document->appendChild($attr);
}
/**
* Load an xslt stylesheet.
*
* @return void
*/
private function loadStyleSheet($stylesheet)
{
$this->xslt = new \DomDocument('1.0', 'UTF-8');
$this->xslt->load($stylesheet);
$this->proc->importStyleSheet($this->xslt);
if (isset($_SERVER['HTTP_HOST'])) {
$this->proc->setParameter('', 'host', $_SERVER['HTTP_HOST']);
}
//$this->proc->setParameter('', 'server', $this->getRequest()->getBaseUrl());
}
private function addSpecInformation(\DOMNode $document, $information)
{
$setSpecAttribute = $this->xml->createAttribute('Value');
$setSpecAttributeValue = $this->xml->createTextNode($information);
$setSpecAttribute->appendChild($setSpecAttributeValue);
$setSpecElement = $this->xml->createElement('SetSpec');
//$setSpecElement =new \DOMElement("SetSpec");
$setSpecElement->appendChild($setSpecAttribute);
$document->appendChild($setSpecElement);
}
}