I have a problem with accessing the crdate of a fe_user in a croniob task. I have an extended Frontend user model where I added this adjustments:
https://stackoverflow.com/a/50663006/1684975
Additionaly I've added a mapping via ts
config.tx_extbase {
persistence {
classes {
TYPO3\CMS\Extbase\Domain\Model\FrontendUser {
subclasses {
Tx_MyExt_User = ACV\MyExt\Domain\Model\User
}
}
Paul\MyExt\Domain\Model\User {
mapping {
tableName = fe_users
recordType = Tx_MyExt_User
columns {
crdate.mapOnProperty = crdate
}
}
}
}
}
}
When I fire up the Scheduler task manual via the Scheduler BE module it's ok. But when the real cronjob kicks in I get the error
Uncaught TYPO3 Exception Call to a member function getTimestamp() on null
In the Scheduler task, I get the crDate via the getter and try to get the timestamp…
$users = $frontendRepository->findByOptIn(false);
foreach ($users as $user) {
if ($user->getCrdate()->getTimestamp() < strtotime('-5 days')) {
$frontendRepository->remove($user);
}
}
The mode of the user is correct. I can access other custom properties I've added to the model.
It's TYPO3 v9.5.26.
The odd thing is that it runs locally in my dev environment.
Did someone have an idea what could cause the problem?
Add a file <extensionfolder>/ext_typoscript_setup.typoscript and add your TypoScript in there:
config.tx_extbase {
persistence {
classes {
TYPO3\CMS\Extbase\Domain\Model\FrontendUser {
subclasses {
Tx_MyExt_User = ACV\MyExt\Domain\Model\User
}
}
Paul\MyExt\Domain\Model\User {
mapping {
tableName = fe_users
recordType = Tx_MyExt_User
columns {
crdate.mapOnProperty = crdate
}
}
}
}
}
}
Alternativly you can add an include there to your TypoScript file in your extension Configuration/TypoScript folder.
If you are in CLI Context, it can be that the TypoScript is not loaded fully for the mapping/extbase configuration, which would match your description that in the BE Context it works, but not in Cronjob/CLI Context.
Related
I need to implement a button in a ListView Command Set extension that is only visible if the user has edit permissions for the selected item in a list. Therefore I have to make an async api call in the onListViewUpdated() method, but I does not seem to work, because onListViewUpdated() cannot be used as a aync function. Does anyone have a solution to that problem?
Check this thread.
#override
public onListViewUpdated(event: IListViewCommandSetListViewUpdatedParameters): void {
// Get commands
const commandOne: Command = this.tryGetCommand('COMMAND_1');
const commandTwo: Command = this.tryGetCommand('COMMAND_2');
// Command checks
if (commandOne) {
this._hideCommandByPermissionSet(commandOne, SPPermission.editListItems);
}
if (commandTwo) {
this._hideCommandByPermissionSet(commandTwo, SPPermission.approveItems);
}
}
private _hideCommandByPermissionSet(crntCommand: Command, permission: SPPermission) {
if (this.context.pageContext.list.permissions.hasPermission(permission)) {
crntCommand.visible = true;
} else {
crntCommand.visible = false;
}
}
I'm trying to create a connection between 2 existing entities PropertyGroup and CustomFieldSet. Use-case is irrelevant.
So I created an EntityExtension:
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new ManyToOneAssociationField('customFieldSet', 'custom_field_set', CustomFieldSetDefinition::class))
);
}
public function getDefinitionClass(): string
{
return PropertyGroupDefinition::class;
}
And override the administration component to also include this association when loading the entity:
Component.override('sw-property-detail', {
methods: {
loadEntityData() {
this.isLoading = true;
const criteria = this.defaultCriteria;
criteria.addAssociation('customFieldSet', new Criteria(1, 500));
this.propertyRepository.get(this.groupId, Shopware.Context.api, criteria)
.then((currentGroup) => {
this.propertyGroup = currentGroup;
this.isLoading = false;
}).catch(() => {
this.isLoading = false;
});
}
}
});
(I tried to override defaultCriteria but that didn't work because of this.$super being unable to access computed properties).
But it keeps saying FRAMEWORK__ASSOCIATION_NOT_FOUND. I debugged the EntityDefinition and it seems that this extension is not even loaded.
I checked if my EntityExtension is loaded in the Symfony container and it is, but it seems that it doesn't reach the entity definition.
The EntityExtension seems to be missing the addition of a FkField inside the function extendFields:
public function extendFields(FieldCollection $collection): void
{
$collection->add(
(new FkField('custom_field_set', 'customFieldSetId', CustomFieldSetDefinition::class)),
);
$collection->add(
(new ManyToOneAssociationField('customFieldSet', 'custom_field_set', CustomFieldSetDefinition::class))
);
}
A new use statement has to be added for the FkField:
use Shopware\Core\Framework\DataAbstractionLayer\Field\FkField;
I know how to fetch data from a custom Generic Inquiry using standard soap / page-based web services.
Here's my code for standard web services to get the results from a custom GI:
static void Main(string[] args)
{
GI000081.Screen context = new GI000081.Screen();
context.Url = "http://localhost/AcumaticaDB181000062/(W(6))/Soap/GI000081.asmx";
context.CookieContainer = new System.Net.CookieContainer();
LoginResult loginResult = context.Login("admin", "Passw0rd");
if (loginResult.Code != ErrorCode.OK)
{
throw new Exception(loginResult.Message);
}
GI000081.Content GI000081Content;
GI000081Content = context.GetSchema(); //.IN202500GetSchema();
//Here's the code to obtain the GI data:
string[][] GI000081Data = context.Export
(new Command[] {
GI000081Content.Result.AccountID,
GI000081Content.Result.Address,
GI000081Content.Result.CustomerID,
GI000081Content.Result.AccountName
},
null, //This is the filter - none here, so null..
0,
false,
false
);
}
My request is, can I get an example of C# code for how to do this using the Contract-based web services. I know how to extend the endpoint and get the wsdl file / service reference to my custom Generic Inquiry, but I don't know the syntax to make the actual call.
Thanks in advance...
Just to make sure that you create the entity in the endpoint properly, make sure that the top level entity contain only the Parameters and that it has a sub entity of type details contain all the results. If there is no parameter then it is fine for the top level entity to be empty.
Here is the code sample that I used
class Program
{
static void Main(string[] args)
{
DefaultSoapClient client = new DefaultSoapClient();
client.Login("admin", "admin", null, null, null);
try
{
BatchPaymentsInq batch = new BatchPaymentsInq
{
Result = new BatchPaymentsInqResult[]
{
new BatchPaymentsInqResult { ReturnBehavior = ReturnBehavior.All }
}
};
var result = client.Get(batch);
}
catch(Exception ex)
{
}
finally
{
client.Logout();
}
}
}
Edit:
Here is how I extended my endpoint in order to use it with the Contract Based SOAP API
So the main entity named BatchPaymentsInq is pointing to the Generic Inquiry screen and will not have any field in it as you have mentioned that there is no parameter.
The sub entity Result is an array of BatchPaymentsInqResult an object created for containing the fields in the result grid of the inquiry.
I have created one demo in mvc 5 and now I need to create one custom filter in my demo. I have used mvc 5.
I need to check every time what method is execute like is a ajax call or action method call in mvc.
Here I have write like this code in my class.
public class UserSession
: System.Web.Http.Filters.ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var session = filterContext.HttpContext.Session;
if (ApplicationSession.IsSessionAlive)
return;
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
var ajaxRedirectTarget = new RouteValueDictionary { { "action", "FailAuthenticationAjax" }, { "controller", "Home" } };
filterContext.Result = new RedirectToRouteResult(ajaxRedirectTarget);
}
else
{
var redirectTarget = new RouteValueDictionary { { "action", "Login" }, { "controller", "Account" } };
filterContext.Result = new RedirectToRouteResult(redirectTarget);
}
}
}
but I got error like this UserSession.OnActionExecuting(ActionExecutingContext): no suitable method found to override
After I have put this class on my controller like this.
[UserSession]
public class DashboardController
{
}
any one know how to fixed this issue in mvc 5?
Is it possible to delete entity while same is still in plugin update transaction?
It seems following code is not working. I need to delete entity when its get updated and some other circumstances
Something like:
protected void ExecutePosAnnotationtUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
if (localContext.PluginExecutionContext.Depth > 1) return;
Entity postEntityImage = null;
if (localContext.PluginExecutionContext.PostEntityImages.Contains("PostImage"))
{
if (localContext.PluginExecutionContext.PostEntityImages["PostImage"] != null)
{
postEntityImage = localContext.PluginExecutionContext.PostEntityImages["PostImage"];
}
}
Entity preEntityImage = null;
if (localContext.PluginExecutionContext.PreEntityImages.Contains("PreImage"))
{
if (localContext.PluginExecutionContext.PreEntityImages["PreImage"] != null)
{
preEntityImage = localContext.PluginExecutionContext.PreEntityImages["PreImage"];
}
}
if ((bool)postEntityImage.Attributes["isdocument"])
{
if ( some condition )
localContext.OrganizationService.Delete(postEntityImage.LogicalName, postEntityImage.Id);
}
}
`
Since you're updating, the record is there in Target.
public void Execute(IServiceProvider serviceProvider)
{
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
var target = context.InputParameters["Target"] as Entity;
var condition = /* whatever */
if(condition)
{
service.Delete(target.LogicalName, target.Id);
}
}
Works as expected when attached to Update message, Post-Operation, Asynchronous. Works inside the Sandbox, also.
Records will not disappear at once, it takes some time (~20 seconds on my on-premise playground). If you make it Synchronous it will still work but alerts are going to come up because data disappears while being handled by the CRM during the update.