How can I run outstanding migrations in laravel4? - command

this is my problem.
I have a migration 2013_08_25_220444_create_modules_table.php within this path :
app/modules/user/migrations/
I have created a custom artisan command:
<?php
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class UsersModuleCommand extends Command {
/**
* The console command name.
*
* #var string
*/
protected $name = 'users:install';
/**
* The console command description.
*
* #var string
*/
protected $description = 'Instala el modulo de usuarios.';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return void
*/
public function fire()
{
echo 'Instalando migraciones de usuario...'.PHP_EOL;
$this->call('migrate', array('--path' => app_path() . '/modules/user/migrations'));
echo 'Done.'.PHP_EOL;
}
/**
* Get the console command arguments.
*
* #return array
*/
protected function getArguments()
{
return array(
//array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
/**
* Get the console command options.
*
* #return array
*/
protected function getOptions()
{
return array(
//array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
In the fire() method, I call the migrate command and also pass an array of options.
then, in my terminal, I run this command:
php artisan users:install
and I this is the output:
Instalando migraciones de usuario...
Nothing to migrate.
Done.
the problem is that the migrations does not run.
But if I run this command in the terminal:
php artisan migrate --path=app/modules/user/migrations
everything works ok, It runs the migration 2013_08_25_220444_create_modules_table.php
Note: I have registered the artisan command in the app/start/artisan.php file:
Artisan::add(new UsersModuleCommand);
What am I doing wrong ?
sorry for my English :D

Notice how the path you passed on the command line is relative to the app root, but the one you passed on your command is absolute? What you should be calling in your command is:
$this->call('migrate', array('--path' => 'app/modules/user/migrations'));
By the way, since you might some day want to rollback these migrations, it is interesting that you add app/modules/user/migrations to your composer.json's classmaps:
composer.json
...
"autoload": {
"classmap": [
...
"app/modules/user/migrations",
]
},

Related

TYPO3: Uploads in backend module

I have to implement a "Book" management in the Backend. Each book has a PDF preview, a title, description and so on...
The BE user should be able to upload a PDF and set a title, description etc. through a Backend module.
The created Book should be selectable in a plugin (or content element ?) so it can be display in the frontend.
Also, the uploaded PDF should only be downloadable by a certain group of FE users.
I don't know how to handle the upload part in the backend. I didn't find much info online beside this upload example: https://github.com/helhum/upload_example it seems quite complex and I'm not sure if it's the best solution for me.
What would be the best way to proceed for my task ?
Use File Abstraction Layer (FAL). You don't need the example in backend, but it's great for frontend upload.
Domain/Model/Book.php
...
/**
* File (file references)
*
* #var \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference>
* #lazy
*/
protected $files = NULL;
/**
* Construct
*
*
*/
public function __construct() {
//Do not remove the next line: It would break the functionality
$this->initStorageObjects();
}
/**
* Initializes all ObjectStorage properties
* Do not modify this method!
* It will be rewritten on each save in the extension builder
* You may modify the constructor of this class instead
*
* #return void
*/
protected function initStorageObjects() {
$this->files = new \TYPO3\CMS\Extbase\Persistence\ObjectStorage();
}
/**
* Set files (file references)
*
* #param \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $files
* #return void
*/
public function setFiles(\TYPO3\CMS\Extbase\Persistence\ObjectStorage $files) {
$this->files = $files;
}
/**
* Get files (file references)
*
* #return \TYPO3\CMS\Extbase\Persistence\ObjectStorage<\TYPO3\CMS\Extbase\Domain\Model\FileReference> $files
*/
public function getFiles() {
return $this->files;
}
...
TCA/tx_yourextension_domain_model_book.php
...
'files' => [
'label' => 'LLL:EXT:werkhandkunst/Resources/Private/Language/locallang_db.xlf:file',
'config' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getFileFieldTCAConfig(
'files', ['
maxitems' => 25,
],
$GLOBALS['TYPO3_CONF_VARS']['GFX']['imagefile_ext']
),
],
...
ext_tables.sql
CREATE TABLE tx_yourextension_domain_model_book (
...
files int(11) unsigned DEFAULT '0' NOT NULL,
...
)

Symfony2 mapping file not found

I have a little form, with just a file field to upload a document. I'm using Symfony2.6 with mongodb annotation. I get a "No mapping found for field 'file'" exception.
My document class :
namespace My\Bundle\Document;
use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;
use Symfony\Component\Validator\Constraints as Assert;
/**
* #MongoDB\Document
*/
class ImportFile
{
[...]
/**
* #Assert\File(maxSize = "5M", mimeTypes = {"image/jpeg", "image/gif", "image/png"})
*/
protected $file;
[...]
/**
* #return $file
*/
public function getFile()
{
return $this->file;
}
/**
* #param $file
*/
public function setFile($file)
{
$this->file = $file;
}
(the namespace is correct, i changed it for the post)
Here is my controller with my form builder :
$importFile = new ImportFile();
$form = $this->createFormBuilder($importFile)
->add('file')
->getForm();
The file field should be automatically detected (as it mentioned here http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html) but it doesn't work. If i add:
$form = $this->createFormBuilder($importFile)
->add('file','file')
->getForm();
it works, but i should'nt have to add the file type as it should be automatically detected. what am i doing wrong ?
I think the problem is in your annotation. You added just an assert but no field definition:
/**
* #Field(type="file")
* #Assert\File(maxSize = "5M", mimeTypes = {"image/jpeg", "image/gif", "image/png"})
*/
I hope it helps.
As you mention here:
I don't want this field to be mapped in the database
You should use mapped property at form field definition:
mapped => false
So, this should resolved your problem ( but remeber that after submit, value from file property will not be mapped with your odm Document ):
$form = $this->createFormBuilder($importFile)
->add('file', 'file', array(
'mapped' => false
))
->getForm();
More here: http://symfony.com/doc/current/reference/forms/types/text.html#mapped

Typo3 Extbase AJAX without page typenum

Is there any way to create AJAX calls in Extbase extension without using of page typeNum?
Edit:
Helmut Hummel, a member of the TYPO3 CMS team, measured that using EID with Extbase is slower than using the typeNum approach. But since the typeNum approach is cumbersome to configure, there is a third way developed by him.
The extension typoscript_rendering provides a way to call Extbase actions directly without additional configuration. It contains a ViewHelper that generates such links and can be used like this in a Fluid template:
{namespace h=Helhum\TyposcriptRendering\ViewHelpers}
<script>
var getParticipationsUri = '<h:uri.ajaxAction controller="Participation" action="listByCompetition" arguments="{competition:competition}" />';
</script>
This generates an URI that calls the action "listByCompetition" of my "ParticipationController". You can pass arguments normally.
The only downside is that for security reasons, the extension uses the cHash to validate the request arguments. The cHash is submitted by GET but you cannot pass additional arguments by GET at the same time because it would invalidate the cHash. So if you want to pass form data in such a request, you need to mix GET (for a valid AJAX call) and POST (for submitting user data):
<script>
var createAddressUri = '<h:uri.ajaxAction controller="Address" action="create" />';
$body.on('submit', '#myForm', function(e) {
e.preventDefault();
emailAddress = $('#myForm').find('#email');
if (typeof(emailAddress) === 'string') {
$.ajax({
url: createAddressUri,
type: 'POST',
data: { 'tx_myext_pluginname[address][email]' : emailAddress},
success: function() {
// things to do on success
}
})
}
});
</script>
(Of course this is only a very basic example. You might post whole models etc.)
The EID way:
Yes, you can use the EID (Extension ID) mechanism for that. There is no official statement which way (pageType or eID) should be used for Extbase AJAX calls and it seems to be just a matter of taste.
There is a nice tutorial that can be found here and I copy the source code in here:
<?php
/** *************************************************************
*
* Extbase Dispatcher for Ajax Calls TYPO3 6.1 namespaces
*
* IMPORTANT Use this script only in Extensions with namespaces
*
* Klaus Heuer <klaus.heuer#t3-developer.com>
*
* This script is part of the TYPO3 project. The TYPO3 project is
* free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* The GNU General Public License can be found at
* http://www.gnu.org/copyleft/gpl.html.
*
* This script is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* This copyright notice MUST APPEAR in all copies of the script!
* ************************************************************* */
/** ************************************************************
* Usage of this script:
*
* - Copy this script in your Extension Dir in the Folder Classes
* - Set the Vendor and Extension Name in Line 82 + 83
* - Include the next line in the ext_localconf.php, change the ext name!
* - $TYPO3_CONF_VARS['FE']['eID_include']['ajaxDispatcher'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('myExtension').'Classes/EidDispatcher.php';
*
* Use for Ajax Calls in your jQuery Code:
*
* $('.jqAjax').click(function(e) {
* var uid = $(this).find('.uid').html();
* var storagePid = '11';
*
* $.ajax({
* async: 'true',
* url: 'index.php',
* type: 'POST',
*
* data: {
* eID: "ajaxDispatcher",
* request: {
* pluginName: 'patsystem',
* controller: 'Todo',
* action: 'findTodoByAjax',
* arguments: {
* 'uid': uid,
* 'storagePid': storagePid
* }
* }
* },
* dataType: "json",
*
* success: function(result) {
* console.log(result);
* },
* error: function(error) {
* console.log(error);
* }
* });
*************************************************************** */
/**
* Gets the Ajax Call Parameters
*/
$ajax = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('request');
/**
* Set Vendor and Extension Name
*
* Vendor Name like your Vendor Name in namespaces
* ExtensionName in upperCamelCase
*/
$ajax['vendor'] = 'T3Developer';
$ajax['extensionName'] = 'ProjectsAndTasks';
/**
* #var $TSFE \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
*/
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, 0, 0);
\TYPO3\CMS\Frontend\Utility\EidUtility::initLanguage();
// Get FE User Information
$TSFE->initFEuser();
// Important: no Cache for Ajax stuff
$TSFE->set_no_cache();
//$TSFE->checkAlternativCoreMethods();
$TSFE->checkAlternativeIdMethods();
$TSFE->determineId();
$TSFE->initTemplate();
$TSFE->getConfigArray();
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();
$TSFE->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer');
$TSFE->settingLanguage();
$TSFE->settingLocale();
/**
* Initialize Database
*/
\TYPO3\CMS\Frontend\Utility\EidUtility::connectDB();
/**
* #var $objectManager \TYPO3\CMS\Extbase\Object\ObjectManager
*/
$objectManager = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\ObjectManager');
/**
* Initialize Extbase bootstap
*/
$bootstrapConf['extensionName'] = $ajax['extensionName'];
$bootstrapConf['pluginName'] = $ajax['pluginName'];
$bootstrap = new TYPO3\CMS\Extbase\Core\Bootstrap();
$bootstrap->initialize($bootstrapConf);
$bootstrap->cObj = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('tslib_cObj');
/**
* Build the request
*/
$request = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Request');
$request->setControllerVendorName($ajax['vendor']);
$request->setcontrollerExtensionName($ajax['extensionName']);
$request->setPluginName($ajax['pluginName']);
$request->setControllerName($ajax['controller']);
$request->setControllerActionName($ajax['action']);
$request->setArguments($ajax['arguments']);
$response = $objectManager->create('TYPO3\CMS\Extbase\Mvc\ResponseInterface');
$dispatcher = $objectManager->get('TYPO3\CMS\Extbase\Mvc\Dispatcher');
$dispatcher->dispatch($request, $response);
echo $response->getContent();
//die();
?>
Have a look at the "usage of this script" section that explains how to register the eID. The script works with TYPO3 6.1 and higher.
For TYPO3 6.2 change the following line:
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()->loadConfigurationAndInitialize();
to
\TYPO3\CMS\Core\Core\Bootstrap::getInstance()
For Test Extension.
Include EID in the ext_localconf.php file
## Ajax configuration
$TYPO3_CONF_VARS['FE']['eID_include']['Test'] = \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('test').'Classes/Ajax/EidDispatcher.php';
Create directory in classes – Classes/Ajax/EidDispatcher.php
namespace TYPO3\Test\Ajax;
class EidDispatcher {
/**
* #var \array
*/
protected $configuration;
/**
* #var \array
*/
protected $bootstrap;
/**
* The main Method
*
* #return \string
*/
public function run() {
return $this->bootstrap->run( '', $this->configuration );
}
/**
* Initialize Extbase
*
* #param \array $TYPO3_CONF_VARS
*/
public function __construct($TYPO3_CONF_VARS) {
$ajaxRequest = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('tx_Test_addhours');
// create bootstrap
$this->bootstrap = new \TYPO3\CMS\Extbase\Core\Bootstrap();
// get User
$feUserObj = \TYPO3\CMS\Frontend\Utility\EidUtility::initFeUser();
// set PID
$pid = (\TYPO3\CMS\Core\Utility\GeneralUtility::_GET( 'id' )) ? \TYPO3\CMS\Core\Utility\GeneralUtility::_GET('id') : 1;
// Create and init Frontend
$GLOBALS['TSFE'] = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $pid, 0, TRUE );
$GLOBALS['TSFE']->connectToDB();
$GLOBALS['TSFE']->fe_user = $feUserObj;
$GLOBALS['TSFE']->id = $pid;
$GLOBALS['TSFE']->determineId();
$GLOBALS['TSFE']->getCompressedTCarray(); //Comment this line when used for TYPO3 7.6.0 on wards
$GLOBALS['TSFE']->initTemplate();
$GLOBALS['TSFE']->getConfigArray();
$GLOBALS['TSFE']->includeTCA(); //Comment this line when used for TYPO3 7.6.0 on wards
// Get Plugins TypoScript
$TypoScriptService = new \TYPO3\CMS\Extbase\Service\TypoScriptService();
$pluginConfiguration = $TypoScriptService->convertTypoScriptArrayToPlainArray($GLOBALS['TSFE']->tmpl->setup['plugin.']['tx_Test.']);
// Set configuration to call the plugin
$this->configuration = array (
'pluginName' => $ajaxRequest['pluginName'],
'vendorName' => 'TYPO3',
'extensionName' => 'Test',
'controller' => $ajaxRequest['controller'],
'action' => $ajaxRequest['action'],
'mvc' => array (
'requestHandlers' => array (
'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler' => 'TYPO3\CMS\Extbase\Mvc\Web\FrontendRequestHandler'
)
),
'settings' => $pluginConfiguration['settings'],
'persistence' => array (
'storagePid' => $pluginConfiguration['persistence']['storagePid']
)
);
}
}
global $TYPO3_CONF_VARS;
// make instance of bootstrap and run
$eid = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( 'TYPO3\Test\Ajax\EidDispatcher', $TYPO3_CONF_VARS );
echo $eid->run();
Call From Script
$.ajax({
async: 'true',
url: 'index.php',
type: 'GET',
data: {
eID: "Test",
tx_ExtName_PluginName: {
pluginName: 'Plugin_Name',
controller: 'Controller_Name',
action: 'Action_Name',
}
},
success:function(data){
// code
}
});
I had to change the first 0 of the makeInstance to the id of the page for it to work.
$id = \TYPO3\CMS\Core\Utility\GeneralUtility::_GP('id');
$TSFE = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController', $TYPO3_CONF_VARS, $id, 0);
I used a quick and probably dirty way without typeNum.
I used jQuery ajax call the common way.
My target action ended with the following.
$headers = DivUtilities::createHeader();
foreach ($headers as $header => $data) {
$this->response->setHeader($header, $data);
}
$this->response->sendHeaders();
echo $this->view->render();
exit;
The createHeader Method
/**
*
* #param string $type
* #return array
*/
public static function createHeader($type = 'html')
{
switch ($type) {
case 'txt':
$cType = 'text/plain';
break;
case 'html':
$cType = 'text/html';
break;
case 'json':
$cType = 'application/json';
break;
case 'pdf':
$cType = 'application/pdf';
break;
}
$headers = array(
'Pragma' => 'public',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Cache-Control' => 'public',
'Content-Type' => $cType
);
return $headers;
}
The output is the template of the called action. This can be html, json or whatever u need.

Persisting language fields

In my extbase model, I created getters and setters for the fields t3_origuid, sys_language_uid, and l10n_parent.
When setting these fields and persisting, only the l10n_parent field is updated in the database. Is it possible to change the other fields, without manually querying the database of course.
To set sys_language_uid through extbase you need to use the internal API AbstractDomainObject::_setProperty() with $entity->_setProperty('_languageUid', $languageUid) where $languageUid would be the id of your langage record. You will find a more complete example on forge: https://forge.typo3.org/issues/61722.
You could also use this small service I've written to translate any domain object easily:
<?php
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
use TYPO3\CMS\Extbase\DomainObject\DomainObjectInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Mapper\ColumnMap;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
/**
* Provides services to translate domain objects
*/
class TranslationService implements SingletonInterface {
/**
* #var \TYPO3\CMS\Extbase\Persistence\Generic\Mapper\DataMapper
* #inject
*/
protected $dataMapper;
/**
* Translates a domain object
*
* #param DomainObjectInterface $origin
* #param DomainObjectInterface $translation
* #param int $language
* #throws \Exception
* #return void
*/
public function translate(DomainObjectInterface $origin, DomainObjectInterface $translation, $language) {
if (get_class($origin) !== get_class($translation)) {
throw new \Exception('Origin and translation must be the same type.', 1432499926);
}
$dataMap = $this->dataMapper->getDataMap(get_class($origin));
if (!$dataMap->getTranslationOriginColumnName()) {
throw new \Exception('The type is not translatable.', 1432500079);
}
if ($origin === $translation) {
throw new \Exception('Origin can\'t be translation of its own.', 1432502696);
}
$propertyName = GeneralUtility::underscoredToLowerCamelCase($dataMap->getTranslationOriginColumnName());
if ($translation->_setProperty($propertyName, $origin) === FALSE) {
$columnMap = $dataMap->getColumnMap($propertyName);
$columnMap->setTypeOfRelation(ColumnMap::RELATION_HAS_ONE);
$columnMap->setType($dataMap->getClassName());
$columnMap->setChildTableName($dataMap->getTableName());
$translation->{$propertyName} = $origin;
}
$translation->_setProperty('_languageUid', $language);
}
}
You have define your fields in the TCA.
'sys_language_uid' => array(
'config' => array(
'type' => 'passthrough'
)
)
And the same for the other fields...
there are some tutorials in the web for mapping tables of typo3 with extbase.
this tutorial is in german, but the code speaks for itself.

Zend Controller Action: _redirect() vs getHelper('Redirector')->gotoUrl()

I've read that $this->getHelper('[helper_name]') is preferable to $this->_helper->[helper_name]. What I haven't been able to find any documentation of is which of these is better/preferred: $this->_redirect($url) or $this->getHelper('Redirector')->gotoUrl($url).
Use whatever one suits you, they do exactly the same thing:
/**
* Redirect to another URL
*
* Proxies to {#link Zend_Controller_Action_Helper_Redirector::gotoUrl()}.
*
* #param string $url
* #param array $options Options to be used when redirecting
* #return void
*/
protected function _redirect($url, array $options = array())
{
$this->_helper->redirector->gotoUrl($url, $options);
}