Drupal\node\Entity\Node Object
(
[in_preview] =>
[values:protected] => Array
(
[vid] => Array
(
[x-default] => 1
)
[langcode] => Array
(
[x-default] => en
)
[field_destination] => Array
(
[x-default] => Array
(
[0] => Array
(
[target_id] => 2
)
)
)
Not able to get field_destination value directly. It's a taxonomy term attached with the content type. Any help appriciated.
To build on VJamie's answer.
You will need to either set a use statement at the top of your script;
use Drupal\taxonomy\Entity\Term;
Or, prefix the class instance with the namespace;
$term = \Drupal\taxonomy\Entity\Term::load($node->get('field_destination')->target_id);
That will get rid of the fatals.
You can also use some methods from EntityReferenceFieldItemList:
Gets the entities referenced by this field, preserving field item deltas:
$node->get('field_destination')->referencedEntities();
Hope it will be useful for you
The following code will get you the term object you need.
$term = Term::load($node->get('field_destination')->target_id);
If you need the name of that term you can do the following
$name = $term->getName();
Hope this helps out!
Do this
use Drupal\taxonomy\Entity\Term;
$term = Term::load($node->get('field_destination')->target_id);
$termname = $term->getName();
In drupal8 we used to follow oops approach to get the values.
This is the correct way on how to achieve it
use Drupal\taxonomy\Entity\Term;
function modulename_node_presave(Drupal\Core\Entity\EntityInterface $entity) {
switch ($entity->bundle()) {
case 'programs':
$term = Term::load($entity->get('field_program_names')->target_id);
$name = $term->getName();
$entity->setTitle($name);
break;
}
}
entity property can be accessed directly from any reference type field.
$node = 'myNode';
$termEntity = $node->get('field_taxonomy_reference')->entity;
if ($termEntity instanceof TermInterface) {
$termLabel = $termEntity->label();
}
Related
I'm newer in Perl, sorry for my dumb question.
I searched but I didn't found a way to do this.
I created a class that one attribute need to be a list of objects and I need to call this list later.
I tried to push the objects in a list I receive the message:
Odd number of elements in anonymous hash at...
My package
package Squid;
use strict;
use warnings;
sub new
{
my $class = shift;
my $self = {#_ };
print "Creating new $class\n";
$self->{'filas'} = [];
bless ($self, $class);
return $self;
}
1;
And this is the script:
use Squid;
use warnings;
use strict;
my $fila = FilaSquid->new("nome" => 'Fila 1', "profundidade" => 45);
my $fila2 = FilaSquid->new("nome" => 'Fila 2', "profundidade" => 7);
my $squid = Squid->new("versao" => '1.0', "origem" => 'C:\temp', "filas" => #filas);
print "\nA versao da fila eh ".$squid->{versao};
print "\nA origem da fila eh ".$squid->{origem}."\n";
foreach my $line ($squid->{filas}) {
print $line->{nome}."\n";
}
First problem is this in new.
$self->{'filas'} = [];
You're initializing $self->{'filas'} to an empty array reference. That will blow away anything passed in via new. What you probably want instead is:
$self->{filas} //= [];
Which is the same as:
$self->{filas} = $self->{filas} // [];
// is the "defined-or" operator. That says to only initialize $self->{filas} if it's undefined. It's a bit safer than using ||= because there are some valid things which are false.
Second problem is how you're passing filas to new. That you're initializing $self->{filas} with an array reference is your clue.
my #filas = (1, 2, 3, 4, 5, 6);
my $squid = Squid->new(
"versao" => '1.0',
"origem" => 'C:\temp',
"filas" => #filas
);
This is like saying:
my $squid = Squid->new(
"versao" => '1.0',
"origem" => 'C:\temp',
"filas" => 1,
2, 3, 4, 5, 6
);
You've just stuck an extra bunch of stuff on the end of what's supposed to be an even-sized list to be used as a hash.
The => operator is basically the same as a comma. It doesn't create pairs, it just allows you to leave out quotes around strings on its left hand side. key => #values isn't one pair, it's key => $values[0], $values[1], $values[2], .... new tries to treat that list as a hash, and so long as there's an even number of elements it will "work".
Instead, you need to pass in an array reference. key => \#values.
my $squid = Squid->new(
"versao" => '1.0',
"origem" => 'C:\temp',
"filas" => \#filas
);
Here's a way that you can insert numerous objects into another object without breaking encapsulation. It does not focus on any issues in your existing code, it just answers the question. In this example, Two holds numerous objects of class One. Each inner object has a name:
use warnings;
use strict;
package One; {
sub new {
my ($class, %args) = #_;
return bless {%args}, $class;
}
sub name {
my $self = shift;
return $self->{name};
}
}
package Two; {
sub new {
return bless {}, shift;
}
sub add {
my ($self, %args) = #_;
my $name = $args{name};
$self->{objects}{$name} = One->new(name => $name);
}
sub get_names {
my ($self) = #_;
return keys %{ $self->{objects} };
}
sub inner_obj {
my ($self, $name) = #_;
return $self->{objects}{$name};
}
}
package main;
my $two = Two->new;
$two->add(name => 'obj1');
$two->add(name => 'obj2');
# loop over each inner object by name
for my $name ('obj1', 'obj2'){
print $two->inner_obj($name)->name . "\n";
}
# or let Two give you the list of names back, and iterate
# automatically
for ($two->get_names){
print $two->inner_obj($_)->name . "\n";
}
Note that we're manually adding new objects in the main script. It is just as easy if you need to set up a list of objects within a module and not main... you'd just modify Two::new() to call its add() method internally.
I currently have this statment:
$query = 'SELECT DataStream__c from JUS_Contract__c limit 50';
Which works fine, but I want to only select the datastream when Datavalue = 3;
for example:
$query = 'SELECT DataStream__c from JUS_Contract__c where DataValue__c=3 limit 50';
When this is atempted I get a notice saying:
Trying to get property of non-object
I know this is because DataValue returns something like this:
stdClass Object ( [Id] => [DataValue__c] => 3)
When I do:
$query = 'SELECT DataStream__c from JUS_Contract__c limit 50';
$response = $mySforceConnection->query(($query));
//print_r($response->records);
foreach ($response->records as $record) {
print_r($record);
(for printing I fixed it by doing this: echo $record->DataStream__c; )
However I can not do that in the query, and am unsure how to change it to either a string or a int inside the query so that I can use the where command on it. Any suggestions would be great.
I'm thinking about using the mutate filter and the rename option, but I don't know about the corresponding regex to achieve that:
filter {
mutate {
rename => {
"any_field_with_underscore" => "anyfieldwithunderscore" # i don't know how to write regex for this ...
}
}
}
Can anyone help?
There no indication in the doc that rename{} takes a regexp.
I've seen this done with a ruby{} filter.
As requested, here's some untested Ruby:
begin
keys = event.to_hash.keys
keys.each{|key|
if ( key =~ /_/ )
newkey = key.gsub(/_/, '')
event[newkey] = event.remove(key)
end
}
rescue Exception => e
event['logstash_ruby_exception'] = 'underscores: ' + e.message
end
To build on Alain's answer,
In Logstash >= 5.x, an event object accessor is enforced:
ruby {
code => "
begin
keys = event.to_hash.keys
keys.each{|key|
if ( key =~ /http_/ )
newkey = key.gsub(/http_/, '')
event.set(newkey, event.remove(key))
end
}
rescue Exception => e
event.set('logstash_ruby_exception', 'underscores: ' + e.message)
end
"
}
}
Also see this feature request that would do the same
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
If I have a hash that "describes" attributes of objects i.e. names and types like:
{
column_defs => {
serial_id => { type => INTEGER },
first_name => { type => CHAR(40) },
salary => { type => DOUBLE },
},
}
The actual hash might be changed but I don't think that the definition affects my core question.
What is a good way to check if the types of each field is defined correctly? E.g. that salary is not defined FLOAT or serial_id is not string etc. (but what should or should not be should be configurable)
I am not sure what would be the best way to define these actual "restrictions" and how to apply them on the hash.
It sounds like you just want to do string comparison between values in a file and values in a hash:
use strict;
use warnings;
use 5.010;
my %column_defs = (
serial_id => { type => 'INTEGER' },
first_name => { type => 'CHAR(40)' },
salary => { type => 'DOUBLE' },
);
while (<DATA>) {
my ($column, $type) = split;
if (my $def = $column_defs{$column}) {
say "'$column' should be $def->{type} but is $type" if $def->{type} ne $type;
}
}
__DATA__
salary DOUBLE
serial_id FLOAT
first_name CHAR(20)
foo BAR
Note that for simplicity, I made the column definitions from your snippet into their own hash.
Output:
'serial_id' should be INTEGER but is FLOAT
'first_name' should be CHAR(40) but is CHAR(20)
EDIT: Misread the question, or rather, didn't see the relevant comment until it was too late - doh! This answer is for checking the values of the fields conform to the specs. Maybe you'll want to do that later! ;-)
You can do this kind of checking manually by setting up tests for the different types of data you're looking at and then running them on the data, e.g.
## tests
sub integer {
return 1 if $_[0] =~ /^[0-9]+$/;
return 0;
}
sub string {
return 1 if $_[0] =~ /^[\w\s]+$/;
return 0;
}
sub char_40_ {
return 1 if length($_[0]) <= 40;
return 0;
}
sub double {
(etc.)
...
# set up a dispatch hash
my %d_hash = (
serial_id => \&integer,
first_name => \&char_40_,
salary => \&double,
another_field => \&integer,
more_data => \&string,
);
Then you can check that the data in the fields matches the specs by calling the appropriate sub:
$d_hash{ $field_name }->( $value_of_field )
Depending on how many different types of data you're looking at, and the number of each, you may want to set up specific tests, e.g. CHAR(40) runs a specific test for fields of 40 chars or less, or you could parse the type field and apply a test for CHARs and for length 40 or less.
I must admit I'm not 100% clear what you're asking, but perhaps something like this might be helpful...?
use strict;
use warnings;
use Types::Standard qw( Dict );
use Types::XSD::Lite qw( String Integer Float );
my $check = Dict[
serial_id => Integer,
first_name => String[ maxLength => 40 ],
salary => Float,
];
$check->assert_valid({
serial_id => 999,
first_name => "Alice",
salary => 20_000.00,
});
$check->assert_valid({
serial_id => 999,
first_name => "Bob",
salary => "peanuts", # fails
});
Not 100% clear what you're asking...
When you define an object, you're suppose to use your methods to verify an object. Here's a very simple example:
package Local::Employee;
use strict;
use warnings;
use Carp;
use Scalar::Util qw(looks_like_number);
use feature qw(say state);
sub new {
my $class = shift;
my $first_name = shift;
my $salary = shift;
my $self = {};
bless $self, $class;
$self->serial;
$self->first_name( $first_name );
$self->salary( $salary );
return $self;
}
sub serial {
my $self = shift;
my $bad_boy = shift;
state $serial = 0;
if ( defined $bad_boy ) {
croak( qq(Cannot set serial number. You can only retrieve it.) );
}
if ( not exists $self->{SERIAL} ) {
$self->{SERIAL} = sprintf "%04d", ++$serial;
}
return $self->{SERIAL};
}
sub first_name {
my $self = shift;
my $first_name = shift;
if ( defined $first_name ) {
if ( length $first_name > 40 ) {
croak( qq(First name can't be longer than forty characters.) );
}
$self->{FIRST_NAME} = $first_name;
}
return $self->{FIRST_NAME};
}
sub salary {
my $self = shift;
my $salary = shift;
if ( defined $salary ) {
if ( not looks_like_number $salary ) {
croak( qq(Salary must be numeric) );
}
$self->{SALARY} = $salary;
}
return $self->{SALARY};
}
sub employee {
my $self = shift;
my %employee_hash = %{ $self };
return \%employee_hash;
}
1;
Notice that each of my methods verify their data. Also notice that my new constructor doesn't know how the data itself is stored. It merely calls the methods for each piece of data. You can bless an object and use the various methods before you return the object to the main program.
Also notice that if I return the whole structure, I dereference my hash reference, and then return that hash reference. In other words, when I return my structure, you get a copy of that structure and not the structure itself. Futzing with $employee->{NAME} isn't going to change the actual name of the object.
Is this totally protected? No. A bad player could use Data::Dumper, get the structure of my object, and then set $self->{NAME} = $name instead of calling $self->name($name). There is a concept of Inside-Out Objects, but most developers have agreed it's more trouble than it's worth. Makes debugging really difficult.
Maybe what you want is more flexibility, you want to define an object's structure on the fly, and verify it.
Take a close look at all of my methods, and you can see they're all very similar in how they work. I could almost create a template. In fact, there are template classes like Class::Struct that allow you to create classes on the fly. Class::Struct defines subroutines that act as methods based upon your field names and puts those subroutines in a namespace you've defined as you class. If you have a class called Foo with a method bar, a subroutine called Foo::bar will be defined, and of course it will also create a subroutine Foo::new to use as a constructor. Once you've defined a class, you can use it just like a normal class:
my $foo = Foo->new(-bar => "bar value");
say "The value of bar is: " . $foo->bar";
If I were you, I wouldn't bother to create real classes because it's rather complex. Instead, I would have a class that allows me to create other classes.
Autoloading is a way of defining a single subroutine called AUTOLOAD that allows you to implement multiple methods without you having to define each and every one. When you call a method like this:
$employee->first_name("Bob");
Perl looks through your subroutines for one named first_name. If it can't find one, it looks for one called AUTOLOAD and sends it the parameters and sets $AUTOLOAD to the name of the method being called.
Let's say you have a hash of classes that contains two classes, one employee and one car:
$VAR = {
"employee" => "FIELDS" => {
"first_name" => "string:40",
"serial" => "serial:d09",
"salary" => "float:%8.2f",
}
{
"cars" => "FIELDS" => {
"license" => "string:9",
"make" => "string:20",
"model" => "string:20",
"top_speed" => "integer:4",
}
}
Now imagine a way to create a new class like this:
my $employee = Local::Class->new( "employee", {
-first_name => "Bob",
-salary => 342.95,
},
);
my $car = Local::Class->new( "car", {
-make => "Chevy",
-model => "Lumina",
-engine => "1.2",
},
);
You could use your new constructor subroutine to set all of those fields via the AUTOLOAD subroutine. Once done, you can treat each object as a class. Let's say you want to know the name of the employee:
say "The employee's name is " . $employee->name;
This could be handled by an AUTOLOAD subroutine that sees what type of class employee is, then verifies if name is even a valid method. If it is, it returns the value of that hash key. Let's take a look at setting:
$employee->name("Bob, the one and true King of France. All hale his majesty");
It again uses AUTOLOAD to verify that name is a valid field, and that the value you're setting is a valid name. (In this case, the subroutine will croak with a name too long error).
Is that more what you want to do? You'll have to have a way of creating your class hash, and making sure that it cannot be changed once set. Then, you simply have to be able to use that hash to verify each object you're creating.
Given this collection:
var list = new [] {
"1.one",
"2. two",
"no number",
"2.duplicate",
"300. three hundred",
"4-ignore this"};
How can I get subset of items that start with a number followed by a dot (regex #"^\d+(?=\.)") with distinct numbers? That is:
{"1.one", "2. two", "300. three hundred"}
UPDATE:
My attempt on this was to use an IEqualityComparer to pass to the Distinct method. I borrowed this GenericCompare class and tried the following code to no avail:
var pattern = #"^\d+(?=\.)";
var comparer = new GenericCompare<string>(s => Regex.Match(s, pattern).Value);
list.Where(f => Regex.IsMatch(f, pattern)).Distinct(comparer);
If you fancy an approach with Linq, you can try adding a named capture group to the regex, then filter the items that match the regex, group by the captured number and finally get only the first string for each number. I like the readability of the solution but I wouldn´t be surprised if there is a more efficient way of eliminating the duplicates, let´s see if somebody else comes with a different approach.
Something like this:
list.Where(s => regex.IsMatch(s))
.GroupBy(s => regex.Match(s).Groups["num"].Value)
.Select(g => g.First())
You can give it a try with this sample:
public class Program
{
private static readonly Regex regex = new Regex(#"^(?<num>\d+)\.", RegexOptions.Compiled);
public static void Main()
{
var list = new [] {
"1.one",
"2. two",
"no number",
"2.duplicate",
"300. three hundred",
"4-ignore this"
};
var distinctWithNumbers = list.Where(s => regex.IsMatch(s))
.GroupBy(s => regex.Match(s).Groups["num"].Value)
.Select(g => g.First());
distinctWithNumbers.ToList().ForEach(Console.WriteLine);
Console.ReadKey();
}
}
You can try the approach it in this fiddle
As pointed by #orad in the comments, there is a Linq extension DistinctBy() in MoreLinq that could be used instead of grouping and then getting the first item in the group to eliminate the duplicates:
var distinctWithNumbers = list.Where(s => regex.IsMatch(s))
.DistinctBy(s => regex.Match(s).Groups["num"].Value);
Try it in this fiddle
EDIT
If you want to use your comparer, you need to implement the GetHashCode so it uses the expression as well:
public int GetHashCode(T obj)
{
return _expr.Invoke(obj).GetHashCode();
}
Then you can use the comparer with a lambda function that takes a string and gets the number using the regex:
var comparer = new GenericCompare<string>(s => regex.Match(s).Groups["num"].Value);
var distinctWithNumbers = list.Where(s => regex.IsMatch(s)).Distinct(comparer);
I have created another fiddle with this approach.
Using lookahead regex
You can use any of these 2 approaches with the regex #"^\d+(?=\.)".
Just change the lambda expressions getting the "num" group s => regex.Match(s).Groups["num"].Value with a expression that gets the regex match s => regex.Match(s).Value
Updated fiddle here.
(I could mark this as answer too)
This solution works without duplicate regex runs:
var regex = new Regex(#"^\d+(?=\.)", RegexOptions.Compiled);
list.Select(i => {
var m = regex.Match(i);
return new KeyValuePair<int, string>( m.Success ? Int32.Parse(m.Value) : -1, i );
})
.Where(i => i.Key > -1)
.GroupBy(i => i.Key)
.Select(g => g.First().Value);
Run it in this fiddle.
Your solution is good enough.
You can also use LINQ query syntax to avoid regex re-runs with the help of let keyword as follows:
var result =
from kvp in
(
from s in source
let m = regex.Match(s)
where m.Success
select new KeyValuePair<int, string>(int.Parse(m.Value), s)
)
group kvp by kvp.Key into gr
select new string(gr.First().Value);
Something like this should work:
List<string> c = new List<string>()
{
"1.one",
"2. two",
"no number",
"2.duplicate",
"300. three hundred",
"4-ignore this"
};
c.Where(i =>
{
var match = Regex.Match(i, #"^\d+(?=\.)");
return match.Success;
});